RE:NODE
Browse hosting

Web hosting13 min read

Migrate WordPress to a new host without downtime

Copy the files, move the database, search-replace the URLs without breaking serialised data, test on a hosts file, then cut DNS over with a short TTL.

0 readers

A WordPress migration is four moves: copy the files, move the database, rewrite the site URL everywhere it is stored, then point DNS at the new address. Done in that order, with the TTL lowered a day in advance and the site tested through a hosts file entry before anything public changes, visitors see no interruption at all. Done in the wrong order, they see a half-migrated site for as long as their resolver remembers it.

The dangerous part is not technical. It is that both copies are live at the same time during the switch, so anything written on the old site after your final export - a comment, an order, a draft - exists nowhere afterwards. Everything below is arranged around shrinking that window to a few minutes and knowing exactly what falls into it.

What you are actually moving#

Five things, and only the first two come out of a migration plugin.

  • The files. wp-content is the part that is yours: themes, plugins, uploads, and often a mu-plugins folder that nobody remembers exists. Core files can simply be downloaded fresh from wordpress.org at the far end - there is no reason to copy 60 MB of files you can fetch in a second.
  • The database. Every table with your prefix. Posts, options, users, and whatever tables plugins created - a shop or a forum keeps most of its data in tables core knows nothing about.
  • `wp-config.php`, which you copy for reference and then rewrite. The database credentials will be different on the new host, and reusing the old ones is the most common reason a freshly migrated site shows a database connection error.
  • Things outside WordPress. Redirect rules in .htaccess or the server config, cron jobs the old host ran for you, a robots.txt you edited by hand, IP allow lists, an SMTP API key in a plugin's settings.
  • DNS and the certificate. Whoever holds the zone keeps holding it; only the records change. If the old host was also your DNS provider or registrar, sort that out before migration day rather than during it - nameservers versus DNS records explains which of the three parties you are actually moving.

Write the list down. A migration that fails a week later almost always fails on item four.

Pick a method, and size the site first#

Check two numbers before choosing anything: the size of wp-content and the size of the database. In the panel or over SFTP, that is a folder size and a table-size figure in phpMyAdmin.

Site sizeMethod that worksWhy
Under 500 MB, simple siteMigration pluginDuplicator, All-in-One WP Migration, UpdraftPlus
500 MB-5 GBManual: archive plus SQL dumpPlugins hit PHP limits on export or import
Any size, with shell accessWP-CLIFastest and the least error-prone
A shop with live ordersManual, with a short freezeYou need control of the exact cut moment

Migration plugins are genuinely good on small sites and genuinely unreliable on large ones, for a boring reason: they do the work inside a PHP request, so max_execution_time and memory_limit apply, and a 3 GB uploads folder does not fit in a 30-second request. The failure is usually silent - an archive that is truncated but looks complete. If your site is big, do it by hand; the manual route below has no size limit worth mentioning.

Plan the window and lower the TTL#

DNS records carry a time to live that tells resolvers how long to remember the answer. If your A record has a TTL of 86,400 seconds, some resolvers will keep sending visitors to the old server for a full day after you change it.

  1. Two days before: lower the TTL on the records you will change - the apex and www - to 300 seconds. You must do this far enough ahead that the old, long TTL has expired everywhere.
  2. Check it took. dig +noall +answer example.com prints the record with its remaining TTL. It should count down from 300, not from a bigger number.
  3. Pick the hour. Your quietest hour in your visitors' timezone, not yours. Look at the analytics rather than guessing.
  4. Decide what freezes. For a blog, nothing: a lost comment is survivable. For a shop or a membership site, put the old site into maintenance mode for the ten minutes between the final database export and the DNS change, and say so on the page.
  5. Keep the old hosting paid for two more weeks. It is the rollback plan and it costs less than the incident does.

DNS records explained covers what each record type does if any of that is unfamiliar, and www versus apex domains matters here because both names have to end up on the new host together.

Copy the files#

With shell access on both ends, archive server-side and move one file:

bash
$ cd /var/www/example.com$ tar -czf /tmp/wp-content.tar.gz wp-content$ scp /tmp/wp-content.tar.gz user@new-host:/tmp/

Without shell access, do the same thing through the file manager: create an archive of wp-content on the old host, download the single file, upload it to the new one, extract it in place. Downloading 40,000 small files over SFTP takes hours; downloading one 800 MB archive takes minutes, and that difference is the whole trick. SFTP and the file manager has the connection details.

Leave behind what you do not need:

  • Cache directories: wp-content/cache, wp-content/et-cache, anything a caching plugin generated. All of it regenerates, and stale cache files are a good way to serve the old URLs after the move.
  • Backup plugin archives inside wp-content. They are frequently the largest thing on the disk, and they are copies of a site you are already copying.
  • error_log files, which can be enormous and tell you nothing on the new server.

Then fetch a clean copy of core on the new host, extract it, and put wp-content back over the top. You now have current core files and your own content, with no chance of carrying across something that was modified while you were not looking.

Move the database#

With shell access, dump and load:

bash
$ mysqldump --single-transaction --default-character-set=utf8mb4 \    --add-drop-table -u olduser -p olddb > site.sql$ gzip site.sql

On the new host, create the database and user first, then import. Through phpMyAdmin the same job is Export, then Custom, then the gzip option, and Import at the other end. Three details decide whether the import is clean:

  • `utf8mb4` end to end. Export and import with the same character set or accented characters and emoji arrive as mojibake. This is not repairable by a find-and-replace afterwards.
  • `--single-transaction` takes a consistent snapshot without locking the site, which matters if you are dumping a busy database.
  • Import size limits. phpMyAdmin imports go through PHP, so upload_max_filesize, post_max_size and max_execution_time all apply. A gzipped dump is usually four to eight times smaller and often the difference between working and not. If it still will not fit, split the dump or raise the limits - the php.ini settings that matter covers which ones, and the phpMyAdmin import and export guide covers the panel side.

On RE:NODE, web plans carry two database slots created from the panel with a generated host, user and password. The Open in phpMyAdmin button signs you in with a single-use token that expires after sixty seconds, so you can import the dump in a browser tab without the credentials ever being typed into a form. Put those new credentials into wp-config.php, not the old ones.

Search and replace, the step that breaks sites#

The database is full of absolute URLs: siteurl and home in the options table, every image src in post content, widget and theme settings, and plugin configuration. If the domain is changing, or you are moving from http to https, all of it has to be rewritten.

Do not do it with SQL. This is the single most damaging mistake in a WordPress migration:

sql
-- Do not do this. It corrupts every serialised setting in the table.UPDATE wp_options SET option_value = REPLACE(option_value, 'old.com', 'new.com');

WordPress stores arrays and objects as PHP serialised strings, which record the byte length of each value. Change old.com to newsite.com inside one of those and the stored length no longer matches, so PHP cannot unserialise it and the plugin or widget silently falls back to defaults. Theme options disappear, menus empty, sliders break - and the damage shows up days later, long after you have stopped suspecting the migration.

Use a tool that understands serialisation. With WP-CLI:

bash
$ wp search-replace 'https://old.example.com' 'https://example.com' \    --all-tables --precise --dry-run$ wp search-replace 'https://old.example.com' 'https://example.com' --all-tables

Run the dry run first, read the table of counts, then run it for real. Without shell access, the Better Search Replace plugin does the same job from the admin and also has a dry-run mode. The standalone Search Replace DB script works too, with one rule: delete it the moment you are finished. A script that rewrites your database sitting at a guessable URL is a complete compromise waiting to be found.

If the filesystem path changed as well - /home/olduser/public_html to something else - search for the old path too. A handful of plugins store absolute paths, and they fail in confusing ways when the path no longer exists.

Test before you touch DNS#

You can browse the new site under its real domain name without changing anything public, by telling your own machine where to look. Add one line to your hosts file - C:\Windows\System32\drivers\etc\hosts on Windows, /etc/hosts on macOS and Linux:

code
203.0.113.25    example.com www.example.com

Your browser now resolves the domain to the new server while the rest of the world still goes to the old one. This is the right way to test, because the site sees its own canonical domain: no redirect back to the old host, no half-rewritten URLs, no temporary hostname stored in the database.

Work through a real checklist rather than glancing at the home page:

  • The home page, a post, a category archive, a page with a form, and the search results.
  • /wp-admin: log in, load the plugins screen, check nothing reports a missing table.
  • Permalinks: visit any non-home URL. A 404 on every page but the home page means the rewrite rules are not in place yet.
  • Images: open a post with media and confirm the files load from the new host.
  • A shop: the cart, the checkout up to the payment step, and one test order in the gateway's sandbox.
  • Anything on a schedule: run a cron event manually and see that it completes.

Remove the hosts entry when you are finished. Leaving it in place means that months later you are the only person on earth who cannot see that the site is down.

The cutover itself#

With the TTL at 300 seconds and the new site tested, the switch is short.

maintenance onimport, search-replaceverified by hosts fileresolvers switchdrains for ~5 minutesOld hostfrozen at T-0Final dumpdatabase and new uploadsNew hostimported, testedDNS A recordTTL 300Visitors
The order that loses nothing during a cutover
  1. Put the old site into maintenance mode, or simply accept the risk if nothing is being written.
  2. Export the database again and import it over the copy on the new host. This second pass is usually a few minutes of work and catches everything written since the first copy. Sync any new uploads the same way.
  3. Re-run the search-replace on the fresh import. It is a new copy of the data; the old URLs are back in it.
  4. Change the A record for the apex and for www to the new address. Change nothing else in the zone: MX records stay where they are, which is what keeps mail working.
  5. Watch the new host's console or access log. Traffic should appear within a minute or two and grow as resolvers expire their cached answers.
  6. Leave the old site in maintenance mode rather than deleting it. It is your rollback, and it stops stragglers writing into a database you are abandoning.

The certificate has an ordering problem worth expecting. Issuance verifies that the name really points at the server asking for it, so a certificate for example.com cannot normally be issued on the new host until DNS already points there. That is a window of seconds to minutes between the record changing and the certificate appearing, during which a visitor may see a warning. On RE:NODE the proxy slot handles this: point the A record at the address on that tab and the certificate is issued as soon as the name resolves, then renewed automatically inside its 21-day window. HTTPS and Let's Encrypt explained covers the validation itself.

After the switch, and what goes wrong#

Within the first hour: re-save permalinks in Settings to regenerate the rewrite rules, confirm HTTPS on a few URLs, send a test email from a contact form, and check that scheduled posts and cron events are firing. Within the first week: watch for 404s from URLs you did not know existed, and re-check the search console for crawl errors.

The recurring failures, and what each one means:

Error establishing a database connection. wp-config.php still holds the old host's credentials, or DB_HOST is localhost where it needs a real hostname.

The site redirects to the old domain. siteurl and home in the options table were not rewritten. Override them temporarily with WP_HOME and WP_SITEURL in wp-config.php, then fix the database properly.

Mixed content warnings. Old http:// URLs still in post content. Re-run the search-replace for the scheme, not just the hostname.

Menus empty, theme options reset. Serialised data corrupted by a plain SQL replace. Restore the database from before that step and redo it with a proper tool. There is no partial fix.

Images 404 while posts are fine. The uploads folder did not copy completely, or file ownership prevents the web server reading it. Compare folder sizes on both hosts rather than trusting the transfer.

Email stops. Mail does not follow the web server. MX records stay with your mail provider, and transactional mail from the site needs an SMTP plugin pointed at a provider that will authenticate you - RE:NODE does not host mail, so plan for that rather than discovering it. SPF, DKIM and DMARC explained covers why the records still matter after a move.

Everything works but the site is slow. A fresh install with no page cache, and OPcache still cold. Reinstall the caching plugin and configure it before drawing conclusions - WordPress speed and caching has the order to do that in.

FAQ#

How long does a WordPress migration take?

Preparation is an hour or two, most of it copying files. The actual cutover is five to fifteen minutes. The DNS tail - stragglers still hitting the old server - is as long as your old TTL was when you changed it, which is why lowering it in advance is the single most useful thing you can do.

Will my site go down during the move?

No, if both copies are live and you only change DNS at the end. Visitors reach one working site or the other. What you can lose is writes to the old site after your final export, which is why a short maintenance window matters for a shop and not for a blog.

Can I migrate without changing the domain?

Yes, and it is the easy case: no search-replace is needed for the hostname, only for the scheme if you are also moving to HTTPS. Test with a hosts file entry and the site behaves exactly as it will after the switch.

Should I use a migration plugin or do it manually?

Plugin for a small, simple site; manually for anything over roughly half a gigabyte, anything with a large database, or anything where you need to control the exact moment of the cut. Plugins run inside PHP requests and fail on the same limits that make big sites big.

What do I do with the old hosting?

Keep it paid and in maintenance mode for two weeks. It is your rollback for the first day and your reference for the fortnight after, when you discover a cron job or a redirect rule you never knew about. Take a final full copy before cancelling.

Do I need to tell search engines the site moved?

Not if the domain is unchanged - they will not notice, and they should not. If the domain did change, keep the old domain alive with 301 redirects to the matching URLs on the new one, and keep them for at least a year.


Comments

Completely anonymous: no account, no email, no cookie. We store the name you type, the text and the time - nothing else. Links are limited and markup is not rendered.

0/2000