---
title: "The WordPress Migration Checklist, Including The Step Most People Skip"
url: https://hostmy.blog/how-to-migrate-wordpress-site/
date: 2026-09-09
modified: 2026-09-03
lang: en
author: "Aditya Sharma"
description: "The migration checklist, including the redirect step people skip and the traffic it quietly costs."
categories:
  - "WordPress"
image: https://hostmy.blog/wp-content/uploads/2026/09/hmb-card-1848-1024x538.jpg
word_count: 1822
---

# The WordPress Migration Checklist, Including The Step Most People Skip

A migration can look flawless on the day it happens. Every page loads, the database matches, images resolve, forms send, checkout works, and the site owner signs off the same afternoon.

Organic traffic then falls away over the following three weeks.

The cause is a few hundred redirect rules sitting in an `.htaccess` file on the old Apache server, left over from a URL restructure years earlier. The migration moves the database and `wp-content`. It does not move server configuration, because migration tools do not. If the new stack is nginx, even a copied `.htaccess` would have done nothing.

Every one of those old URLs starts returning 404. They are still receiving traffic and still holding links. Rebuilding the map from Search Console, the Wayback Machine and the last month of old access logs is a full day of work, and the traffic takes weeks to come back.

That failure mode is the reason this checklist exists, and the reason the boring inventory step comes first.

## Inventory the things that do not live in the database

The database and `wp-content` are the easy part. Every migration tool handles them. What gets lost is everything outside those two places.

Go through this list on the old server before you touch anything:

| Thing | Where it hides | What happens if you miss it |
| ----- | -------------- | --------------------------- |
| Redirect rules | `.htaccess`, nginx config, host control panel | Old URLs 404, traffic disappears quietly |
| Must use plugins | `wp-content/mu-plugins` | Silent behaviour changes, or a fatal if half copied |
| Object cache drop in | `wp-content/object-cache.php` | Points at a Redis host that no longer exists |
| Cron | System crontab, or `DISABLE_WP_CRON` in wp-config | Scheduled posts stop, backups stop, nothing errors |
| Transactional email | SMTP plugin credentials, SPF and DKIM records | Password resets and order emails go to spam |
| PHP version and extensions | Host panel | Fatal errors on plugins that need an extension |
| SSL certificate and forced HTTPS | Server config | Mixed content, or a redirect loop |
| `wp-config.php` constants | The file itself | Memory limits, keys, debug flags all reset to defaults |
| Files outside the WordPress root | Anywhere | Verification files, ad tag files, downloadable assets |

The redirect line is the one that cost us. Export it explicitly, as a text file, before anything else happens. If the redirects live in a plugin they will come across in the database. If they live in server config they will not. The PHP version line is the next worst: match it exactly on the new server first and treat [any move to a newer PHP or MySQL release](/wordpress-php-version/) as a separate, deliberate change, so you are never debugging two of them at once.

The migration order, and the step people skip

The migration order, and the step people skip

Inventory what does not live in the database
cron, mail, DNS, certificates, uploads

Take a backup and restore it somewhere
a backup nobody has restored is a hope

Move files and database, then fix URLs
a search-replace that understands serialised data

Test on the new server before DNS moves
a hosts file entry, not a live switch

Cut over with a low TTL and a rollback
lowered days in advance

Watch the next 48 hours
this is where the damage shows up

Every row above the cutover is reversible. The TTL row is not, which is why it is lowered days in advance rather than on the day.

## Take a real backup, and prove it is real

Not the migration tool's export. A separate, restorable backup of the old site, taken and verified before you begin.

The reason is specific. A migration that goes wrong halfway leaves you needing to go back, and the moment you need to go back is the moment you discover that your backup was a hypothesis. That is exactly the trap described in [the restore test most schedules skip](/wordpress-backup/).

Verify by counting. Import the dump somewhere throwaway and check the published post count matches production. A smaller dump also imports faster, which is a fair argument for [clearing out revisions and expired transients](/wordpress-database-maintenance/) before the move rather than after it.

`wp db export pre-migration.sql --allow-root
wp post list --post_type=post --post_status=publish --format=count --allow-root`

## Move the files and the database, then fix the URLs properly

The mechanics are simple. Copy `wp-content`, import the database, update `wp-config.php` for the new database credentials.

The URL replacement is where people damage things. Do not run a plain SQL find and replace. WordPress stores serialized arrays in `wp_options` and `wp_postmeta`, and serialized data carries the byte length of each string. Change the string without changing the length prefix and the array becomes unreadable. Widget settings, theme options and page builder layouts vanish, usually without an error.

Use a tool that understands serialization, and dry run it first:

`wp search-replace 'https://old-domain.com' 'https://new-domain.com' --all-tables --precise --dry-run --allow-root
wp search-replace 'https://old-domain.com' 'https://new-domain.com' --all-tables --precise --allow-root`

Run it for the protocol relative and www variants too if the old site used them. Then check `wp_options` for the two rows that matter:

`wp option get siteurl --allow-root
wp option get home --allow-root`

## Test on the new server before DNS moves

Point your own machine at the new server with a hosts file entry, so you see the new site under the real domain name while everybody else still sees the old one.

`203.0.113.10 example.com www.example.com`

Then work through the list. Not the homepage. The list:

- One post of each type: standard article, a post with a gallery, the oldest post you have, a post using a shortcode.

- Every form. Submit each one and confirm the email arrives, in the inbox rather than spam.

- Login, password reset, and any membership or paywall flow.

- Search results.

- The 404 page, so you know it renders and returns an actual 404 status.

- Ten of the redirect rules you exported earlier, chosen at random.

- The sitemap, and `robots.txt`.

That last pair is worth its own warning. Staging environments are usually set to discourage indexing, one of several ways [a staging copy quietly stops matching production](/wordpress-staging/). If that setting travels with the database, you go live with a site telling search engines to stay away, and nothing about the site looks wrong.

`wp option get blog_public --allow-root # must return 1 on production
curl -sI https://example.com/robots.txt`

The same category catches the AI crawler files. robots.txt rules, an llms.txt, and any Markdown copies of your posts are generated output rather than database rows, so they need regenerating on the new server instead of being assumed to have travelled. [RankReady](https://wordpress.org/plugins/rankready-ai-llm-seo/) is the WordPress AI SEO plugin we use to hold that layer, version 1.3.1, tested to WordPress 7.1, with around 300 active installs on WordPress.org. It runs alongside Rank Math, Yoast, AIOSEO or SEOPress without conflicting with them, takes roughly five minutes to configure, and after a move you reopen it once to confirm those files are being served. That is a crawlability check, and it does nothing about your redirects.

## Cut over with a low TTL and a real rollback

Lower the DNS TTL to 300 seconds at least 24 hours before the move, so the old value has expired everywhere by the time you switch. Otherwise a 24 hour TTL means some visitors keep hitting the old server for a full day after you change the record.

Keep the old server running, untouched, for at least a week. Two things depend on that. It is your rollback, and it is where the traffic goes for whichever resolvers are still caching the old address.

If the site accepts orders, comments or form submissions, put it into a read only or maintenance state during the window between the final database export and the DNS switch. Otherwise you will end up with writes on the old server that never make it to the new one. On a busy site those writes are orders.

## The 48 hours after, which is where the damage shows up

Day one looks fine on almost every failed migration we have seen. The damage surfaces later, which is why this window has its own checklist.

**Watch the 404 log.** This is the single check that would have caught our redirect disaster in hours instead of weeks. A spike in 404s after a migration is always something you moved incorrectly.

**Check that scheduled posts publish.** If cron was running as a system job on the old server and nobody set it up on the new one, WordPress falls back to its own pseudo cron, or does nothing at all if `DISABLE_WP_CRON` came across in `wp-config.php`. The symptom is a post stuck at "Missed schedule" and no error anywhere.

**Send a test email from the site, to a Gmail address.** New server, new sending IP. If the SPF record still authorises only the old host, your mail is now unauthenticated.

**Resubmit the sitemap and watch Search Console coverage.** You are looking for a rise in "Not found" or "Redirect error", not for ranking changes, which are noise at this timescale.

**Confirm HTTPS is forced and there is exactly one redirect hop.** A common mess after migration is `http` to `https` to `www` to final, three hops where one belongs.

**Check response times against the old server.** If the new host is slower under real traffic, you want to know in week one while rolling back is still easy. The measurement approach is in [speed work that showed up in the numbers](/wordpress-speed-optimization/).

## The parts people skip and regret

Ranked by how often we have had to clean them up afterwards.

- **Server level redirects.** Described above at length, because it is first by a distance.

- **Email deliverability.** Silent, and it breaks password resets, which breaks customers.

- **Cron.** Silent, and it breaks backups, which you only discover during an emergency.

- **The indexing flag.** One checkbox, weeks of damage.

- **Host specific plugins left installed.** A caching plugin built for the old platform will try to purge a cache that no longer exists, and sometimes fatals doing it.

- **File permissions and ownership.** Uploads fail, or worse, everything is writable by the web server.

- **Hardcoded absolute URLs in theme templates.** Not in the database, so the search and replace never touches them.

## Ask about migration before you pick a host, not after

The easiest migration is the one you set up correctly at the start. Two questions to ask any host you are considering: can you download a complete restorable backup yourself without opening a ticket, and what platform specific code do they inject into your site. That second question is covered in more depth in [what a managed plan is really selling](/managed-wordpress-hosting/).

We migrate client sites as part of onboarding, and we run this checklist every time, including on sites we are told are simple. The 48 hour window then hands straight over to [the ordinary monthly upkeep a site needs](/wordpress-maintenance-service/), because most of what a migration breaks surfaces on the same checks. If you want somebody else to hold it, that is a service we sell. If you want to run it yourself, everything above is the whole thing.

One question to end on: if you moved your site tomorrow, could you list every redirect rule currently protecting your old URLs?