MigrationJuly 10, 20268 min read

How to migrate WordPress without 404ing old URLs (the steps most freelancers skip)

Copy files, copy database, update wp-config - and images break, links point at the old host, old URLs 404. The checklist: serialized search-replace, DNS cutover, 301 map. Rankings are not guaranteed.

By Dmitriy Gabdrakhmanov. Operator, WPSERVICE LAB.

WordPress migration sounds simple. Copy files, dump the database, update wp-config.php. Then the agency loads the client site: broken images, admin still pointing at the old host, SSL missing, half the URLs 404. Google is not a promise. Those 404s are.

This is why people pay for migrations. The file-and-database copy is 20% of the work. The other 80% is the stuff that breaks when you do it wrong.

Why migrations break - the serialized data trap

Here's the core problem: WordPress stores your domain name in the database - not just in obvious places like siteurl and home in the wp_options table, but serialized inside PHP arrays in widget settings, menu configurations, and theme options.

A serialized string looks like s:21:"https://old-site.com". The 21 is the string length. If you do a naive find-and-replace from old-site.com to new-site.com, the URL changes but the length doesn't - and PHP's unserialize fails because the length no longer matches. Your widgets vanish. Your menu disappears. Your theme options reset.

This is the #1 migration mistake: running a SQL find-and-replace on serialized data. It corrupts the serialized strings and silently breaks your site.

The correct way: search-replace that handles serialization

You need a tool that deserializes, replaces, and re-serializes correctly. Two options:

WP-CLI (recommended for VPS/managed hosts)

If your host has WP-CLI, run:

wp search-replace 'https://old-site.com' 'https://new-site.com' --all-tables

This handles serialization correctly and updates every table. It's fast, reliable, and the standard approach.

WP Migrate DB or Better Search Replace (for shared hosting)

If you don't have WP-CLI, use a plugin. WP Migrate DB (free) or Better Search Replace (free) both handle serialization correctly. Install on the old site, export a find-replace database dump, import on the new host.

The full migration checklist

Here's the sequence that keeps old URLs from 404ing:

Phase 1: Prepare (don't touch the live site yet)

  • Back up everything. Files (via FTP or host backup) + database (via phpMyAdmin export or WP-CLI db export). If the migration fails, you restore from this.
  • Set up the new host. Install a fresh WordPress, note the new database credentials.
  • Check DNS access. Make sure you can edit DNS records for the domain (at Cloudflare, your registrar, or wherever DNS lives).

Phase 2: Copy (old → new)

  • Copy files: wp-content/ (uploads, themes, plugins) from old host to new. Skip wp-config.php - use the new host's version.
  • Export database: From old host, full SQL dump.
  • Search-replace: Run the URL replacement (WP-CLI or plugin) to update old-site.comnew-site.com across all tables.
  • Import database: On new host, import the search-replaced SQL dump.

Phase 3: Test (on the new host, before DNS cutover)

This is the step most freelancers skip - and it's why migrations fail at 2am. Edit your local hosts file to point the domain at the new host's IP:

NEW_HOST_IP your-domain.com
NEW_HOST_IP www.your-domain.com

Now your browser loads the new host while the rest of the world still sees the old one. Test: homepage, inner pages, images load, admin panel works, forms submit, WooCommerce checkout completes, permalinks aren't 404ing.

Phase 4: DNS cutover (the actual move)

  • Lower TTL on DNS records 24h before (to 300s) so the cutover propagates fast.
  • Pick a low-traffic time (late night, weekend).
  • Update the A record to the new host's IP.
  • Keep the old host live for 48-72h - during DNS propagation, some visitors still hit the old server. Don't shut it down early.

Phase 5: Post-migration (SSL and the 301 map)

  • SSL: Install the certificate on the new host before cutover. A site that loads over HTTP after migrating from HTTPS will 404 or warn on every old HTTPS URL.
  • 301 redirects: If any URLs changed (e.g., permalink structure, or old paths removed), add 301 redirects in .htaccess or Nginx config. Without them, those URLs 404.
  • Update sitemap: Regenerate sitemap.xml on the new host and resubmit in Google Search Console.
  • Check Search Console: After 48h, check for new 404s or crawl errors. Fix immediately.

The two mistakes that actually 404 old URLs

1. URLs that 404 after migration

If your permalink structure changed, or some pages weren't copied, old URLs return 404. Google drops them from the index within days. Always set up a 301 redirect map - for every old URL that no longer exists, redirect to the closest relevant new URL. That stops the 404. It is not a ranking promise.

2. HTTP instead of HTTPS

If the new host doesn't have SSL configured at cutover, browsers show a security warning. Visitors bounce. SSL must be live on the new host before DNS points to it. Use Let's Encrypt (free) or your host's free SSL.

When to hire someone (vs. DIY)

If you have one WordPress site, no custom code, and a host with a staging environment - you can migrate it yourself with a plugin like Duplicator or All-in-One WP Migration. Budget 2-4 hours.

Hire a professional when:

  • You have a 301 map to ship. One missed redirect leaves old URLs as 404s. A professional maps every URL and sets up redirects before cutover.
  • It's a WooCommerce store. Migrating a store means orders, customers, and payment gateway configs. Get one thing wrong and checkout breaks.
  • It's a multi-site or network. Multi-site migrations are fundamentally different - database tables, domains, and site mapping all need special handling.
  • Email is on the same host. If you're migrating the host that also handles email, you need to migrate mailboxes and MX records without downtime. This is where DIY attempts go catastrophically wrong.

If you are moving a client roster or a store, send old host, new host, domain, and whether email or WooCommerce is on the same box. Fixed price before cutover. Rankings are not a promise. The 301 map is. Message @wpservicelab on Telegram.

Moving a client roster or a store?

Send old host, new host, and the domain. Rankings are not a promise. The 301 map is.

Migration scope and pricing
Send old host / new host