
Most WordPress migrations fail quietly. The site loads, the logo is there — and then you find that serialized widget settings are corrupted, some images 404, or the certificate covers the wrong hostname.
This procedure is ordered to prevent that. It assumes SSH on both ends, which is the case that always works.
Before you touch anything
- Take a verified backup of files and database. Verified means you can list the archive contents, not that a file exists.
- Record the current DNS TTL. If it’s 24 hours, drop it to 300 seconds now and wait out the old TTL before switching. This is the step people skip and then wait a day for.
- Note your PHP version and match it on the destination. A plugin running fine on 8.3 may refuse to load on 8.1.
- Inventory what lives outside the WordPress directory: cron jobs, custom nginx rules, server-level cron for plugins, anything non-standard in
wp-config.php.
The migration itself
Build the destination first, on its temporary hostname or IP, with SSL for that name. Test it there before any DNS changes.
- Copy files. Archive with ownership preserved, transfer, extract.
rsync -ais fine and resumable. - Export the database with
mysqldump --single-transaction. The flag matters on InnoDB: no table locking, and a consistent snapshot. - Import, then fix URLs in the database before DNS points anywhere.
sed on a dump. WordPress stores widget settings, theme options and some plugin config as PHP-serialized arrays containing string lengths. The moment a URL changes length, the length prefix is wrong and the data is unreadable. Use WP-CLI’s search-replace, which deserializes and re-serializes properly.With WP-CLI on the destination:
wp search-replace 'https://old.example' 'https://new.example' --all-tables --precise --report-changed-only
--precise makes the command refuse to proceed if serialized data won’t round-trip cleanly. Don’t skip it.
The checks that catch quiet failures
- Permalinks. Visit Settings → Permalinks and save once. Rewrite rules live in the database and may still point at old paths.
- Serialized data. Open a widget or theme options screen. Empty fields or arrays rendered as text mean a serialization break.
- Media. Spot-check images inside posts, not just the library grid. Some themes hardcode absolute URLs in custom fields.
- SSL. Confirm the certificate covers both
example.comandwww.example.comif you use both, and that the console shows no mixed content. - Email. Send a test from a form. Migrations break sending constantly, because the new host blocks the mail port or the old SMTP credentials are gone.
- Cron. Verify WP-Cron runs, or that server cron calls
wp cron event run --due-now. Scheduled posts that never publish are usually this.
Then switch DNS
Point DNS at the new host. Keep the old server alive and reachable for at least a week — not serving the domain, just holding data in case something surfaces late. Some visitors and crawlers will hold the old IP for the previous TTL.
After cutover
- Submit the sitemap in Search Console. Use change-of-address only if the domain changed.
- Watch error logs for 404 spikes on URLs you’d forgotten existed.
- Search-replace any remaining references to the temporary hostname.
- Cancel the old host after the grace period, once you’ve confirmed backups on the new one run and restore.
Questions people ask
How long does a migration take?
The file copy dominates and scales with media. A small site takes under an hour including verification. A large library over a slow link can take most of a day — start the rsync early and let it resume.
Can I migrate without SSH?
Yes, with a plugin, and it works reasonably for small sites. You give up visibility into serialization handling and logs, which is exactly what you want when something goes wrong.
Will I lose SEO rankings?
If URLs stay identical and the domain doesn’t change, usually not. Rankings drop when URLs change without redirects, or the new host is slower.
Sources
- https://developer.wordpress.org/cli/commands/search-replace/
- https://developer.wordpress.org/advanced-administration/security/backup/
- https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html
Some links on this page are affiliate links. If you buy through them, TechPicks may earn a commission at no extra cost to you. It does not affect what we recommend. Full disclosure.