Migrating WordPress sites: practical tips and trade-offs
Migrating a WordPress site from one server to another is one of those tasks that looks straightforward on paper but can unravel quickly if you skip the details. We've all heard the horror stories—a site moves, URLs break, WooCommerce orders stop processing, or login redirects loop endlessly. This guide walks through the core steps we follow when migrating WordPress sites in production, the real gotchas we've hit, and how to validate everything works before your users notice anything went wrong.
Export files and database — wp db export plus wp-content
The foundation of any migration is a complete snapshot: your database and your files. We start by treating these as separate concerns, because they often have different size and transport constraints.
For the database, the WordPress CLI command is your friend:
wp db export /tmp/wordpress_prod_backup.sqlThis dumps your entire database to a single SQL file. On a mature site with millions of posts or comments, this can be large—sometimes 500 MB to several GB—so verify disk space first. If you're exporting from a managed host with limited temp storage, pipe directly to your local machine via SSH:
ssh user@oldserver.com "wp db export -" > wordpress_prod_backup.sqlFor the files, you're looking at wp-content primarily. This folder holds themes, plugins, and uploads—everything that makes your site unique. Use rsync if you have SSH access, as it only transfers changes on subsequent runs:
rsync -avz --delete user@oldserver.com:/var/www/html/wp-content/ ./wp-content/The --delete flag ensures deleted files on the source are removed from the destination, preventing orphaned assets. If you're using a plugin like Duplicator or All-in-One WP Migration, you get a packaged export that bundles everything, which simplifies transport but can be slower on very large sites.
Verify the export completed successfully by checking file sizes and spot-checking a few recent posts in the SQL dump. We've seen truncated exports cause silent failures midway through a migration.
Search and replace URLs — wp search-replace handles serialized data
Once you have your files and database on the new server, your URLs are almost certainly wrong. If your old site was https://example.com and your new home is https://newexample.com, hardcoded URLs throughout the database need to change.
The tempting approach is a raw SQL UPDATE, but WordPress stores data in serialized PHP arrays. A post with metadata like a:3:{s:4:"url";s:15:"https://example.com";} cannot be safely updated with simple string replacement—the byte count in the serialization will be wrong, and WordPress will fail to unserialize it.
WordPress CLI's search-replace command handles this correctly:
wp search-replace 'https://example.com' 'https://newexample.com' --all-tablesThe --all-tables flag ensures it scans every table, not just core WordPress tables, which matters if plugins store serialized data in custom tables. By default, it does a dry run—add --execute to commit changes:
wp search-replace 'https://example.com' 'https://newexample.com' --all-tables --executeIn a real scenario, we migrated a travel site from travel.local to travel.co.uk. Without proper search-replace, booking confirmation emails still linked to travel.local, and affiliate tracking pixels were broken. The serialized data in WooCommerce order metadata would have caused checkout errors.
If you're running WordPress in a subdirectory, or if your site has both http and https variants, do multiple passes:
wp search-replace 'http://example.com' 'https://newexample.com' --all-tables --execute
wp search-replace 'https://example.com' 'https://newexample.com' --all-tables --executeAfter running search-replace, log in to the WordPress admin and check Settings > General to confirm the WordPress Address and Site URL are correct. These are the source of truth, and everything else should flow from them.
DNS cutover — Lower TTLs before switching
DNS is often the weak link in migrations. A DNS TTL (time to live) of 3600 seconds (one hour) means some of your users will still hit the old server for up to an hour after you change DNS records, even if you've updated them. During that window, any changes you make to the new site won't be visible to everyone.
Best practice is to lower your TTL days before the migration—usually to 300 seconds (5 minutes) or even 60 seconds. This trades query load for faster propagation:
| TTL | Max delay after DNS change | When to use |
|---|---|---|
| 86400 (24 hours) | Up to 24 hours | Stable, rarely-changed records |
| 3600 (1 hour) | Up to 1 hour | Default for most sites |
| 300 (5 minutes) | Up to 5 minutes | Pre-migration, few days before cutover |
| 60 (1 minute) | Up to 1 minute | During active migration, 2-4 hours before/after |
We typically lower TTLs three days before a migration, monitor them settling, then perform the cutover during a maintenance window when traffic is low. For a SaaS product or e-commerce site, we aim for 2-4 AM in the timezone of our heaviest users.
Once you've changed the DNS A record to point to your new server's IP, use nslookup or dig to verify propagation:
dig +trace newexample.comThis shows you the full resolution path. Cross-check with public DNS checkers like DNS Checker or MXToolbox to see global propagation. Expect 15 minutes to 2 hours for most of the internet to catch up, depending on your registrar and DNS provider.
After DNS has settled, raise the TTL back to normal (usually 3600). No need to keep it low and hammer your DNS provider once the migration is done.
Test — Check forms, logins and payments after migration
Testing is where we catch most of our mistakes. We follow a checklist before considering a migration complete:
- Frontend rendering: Visit the home page, a post, a product page (if e-commerce). Check images load, styles apply, and no JavaScript errors appear in the browser console.
- Admin access: Log in as admin. Verify you can edit posts and access all admin pages. Watch for redirect loops, which often indicate misconfigured
siteurlor SSL settings. - Forms: Submit a contact form, sign up for a newsletter, anything that POSTs data. Check that submissions are recorded and emails are sent. Form endpoints sometimes break if they rely on hardcoded URLs.
- User authentication: Create a test user and log in as them. Verify role-based access control works (editors can edit, subscribers can only view, etc.).
- Payments (if applicable): For WooCommerce or Stripe sites, place a test order. Ensure payment processing, order confirmation emails, and order history pages all function. Check that webhook endpoints are reachable from the payment provider's servers.
- Email delivery: Test email sending from forms, password resets, and plugin notifications. Email often breaks due to SPF/DKIM/DMARC records not matching the new server's hostname.
- Redirects: Old URLs should redirect to new ones (via 301 permanent redirects). Test a handful of known old URLs.
- Performance: Load the site in an incognito tab to avoid browser cache. Check page load time. If it's noticeably slower, investigate database size, plugin count, or missing CDN configuration.
In practice, we build a simple test matrix in a spreadsheet: URL, expected behavior, actual result. We run this against the new server before DNS cutover, then again an hour after cutover to catch propagation issues.
Common mistakes
- Forgetting to update wp-config.php constants: If your new server has a different database name or user, wp-config.php must match. We've seen sites fail silently because the old database credentials were cached or hardcoded in plugins.
- Ignoring serialized data in search-replace: Using raw SQL or even simple find-and-replace text editors will corrupt serialized arrays. Always use wp search-replace.
- Not testing before DNS cutover: If you wait until after DNS points to the new server to test, you have no fallback if something is broken. Test everything on the new server before the cutover, ideally via hosts file override or temporary DNS changes.
- Skipping SSL certificate setup: If you're moving to HTTPS, ensure your SSL certificate is installed and trusted on the new server. Mixed content (HTTPS page loading HTTP resources) breaks forms and payments.
- Not backing up the old site: Keep a backup of the old server running for at least a week after migration. If a critical issue emerges, you can roll back without data loss.
- Forgetting plugin license keys or API keys: Some plugins require re-activation on a new server. Make a list of plugins that need API keys (WooCommerce extensions, Jetpack, etc.) and re-configure them on the new site.
Key takeaways
- Export your database with
wp db exportand transferwp-contentseparately; both are needed for a complete migration. - Use
wp search-replacewith--all-tablesto handle serialized data correctly; raw SQL updates will corrupt it. - Lower DNS TTLs days before the cutover, then perform the actual DNS change during a maintenance window with low traffic.
- Test login, forms, payments, and email on the new server before DNS cutover; use a hosts file override to visit the new site by URL without changing DNS.
- Keep the old server online for a week post-migration as a safety net; document any manual configuration changes so you can replicate them if needed.
- Verify SPF/DKIM/DMARC records match the new server's hostname if email delivery is critical.






Comments
Loading comments…