Your WordPress site loads on the new host. Has the migration really finished? Check where traffic goes and whether mail, features and backups still work. Every migration guide ends when the new server loads the site; our checks start there. Plugins usually copy files and databases reliably. The failures that follow are quieter: pages still return HTTP 200 while features are broken, old hosting is still billed, or backups are publicly readable.
We move export-facing WordPress sites for a living. These checks come from roughly forty migrations off one shared platform onto self-managed servers, plus individual moves before and after that batch. We found every issue after a migration had already been marked complete.
1. The migration that never actually happened
The most expensive failure is also the least visible: the files and database moved, and DNS never followed.
Nothing looks wrong. The new server serves the site correctly if you visit it by IP or a temporary hostname. The old host keeps serving real traffic. Both copies return 200. Months pass.
We audited a group of sites long after their migration was marked complete and found nine of them still resolving to the old provider’s IP. The copies on the new servers had been sitting there consuming disk and PHP workers with zero traffic, while the old hosting account kept billing.
What made it obvious once we looked at the right thing:
# Where does the world actually reach this site?
dig +short A example.com
dig +short A www.example.com
dig +short AAAA example.com
dig +short AAAA www.example.com
dig +short CNAME www.example.com
Compare the answers with the new server address. A mismatch is not automatically a failure. With a CDN, reverse proxy or load balancer, the public record is supposed to point at the edge. Check the origin setting in the CDN console, then inspect access logs on both servers.
Check AAAA as well as A. A forgotten IPv6 record pointing at the old host will serve a share of your visitors from the old server while the IPv4 record looks perfectly correct.
The decisive evidence is not DNS at all — it is which machine is receiving requests. Look at the access log on the new server and confirm real visitor traffic is arriving, and look at the old one to confirm it has stopped.
A second check that costs nothing and settles it in seconds:
# Newest uploaded file on the new server
find wp-content/uploads -type f -printf '%T+ %pn' 2>/dev/null | sort -r | head -3
On the nine sites above, the newest uploads were all from around the migration date and nothing after — copies frozen since the day they were made, which is what pointed us at the DNS in the first place.
Treat an unchanged uploads directory as a clue. Brochure sites, sites with external media storage, and sites whose editors have not posted may legitimately go months without new uploads. Check the access logs before drawing a conclusion.
Do this check on a fixed schedule after every move — a week later, then a month later. The failure mode here is not a bug, it is an unfinished task that nobody is looking at.
2. The backup archive you left in the web root
Migration plugins build a single archive containing everything, and by default they write it inside wp-content/. That is inside the public web root.
The plugins know this is dangerous, so they drop an .htaccess with deny rules and an empty index.php into the backup folder. On Apache that is usually enough. On OpenLiteSpeed it is not. OpenLiteSpeed does not honour those directives the way Apache does, and we confirmed the consequence from a public connection rather than assuming it:
GET /wp-content/<plugin-backup-dir>/<archive-name>
→ HTTP 200
→ 47,355,082 bytes transferred before we aborted the download
→ first bytes matched the archive format's signature, not an error page
Three other sites on the same server answered ranged requests with HTTP 206, meaning the download is resumable.
Worth being precise about what that archive holds, because it is not just content: the database dump, wp-config.php with the database credentials, administrator password hashes, stored SMTP credentials, and every customer enquiry ever submitted through a form.
There was one limit to the exposure: directory listing returned 200 but showed nothing. An attacker could not list filenames and would have to guess an archive name containing a timestamp. That makes discovery harder, but it is not a dependable access control.
Check every site you have ever migrated:
find /path/to/sites -path '*/wp-content/*'
( -name '*.wpress' -o -name '*.sql*' -o -name '*.tar.gz' -o -name '*.zip' ) -ls
Test from a public connection, because the issue is what visitors can download. If the archive downloads, treat its credentials as exposed: rotate database, administrator and SMTP passwords. Deleting the file does not undo the period of exposure.
The durable fix is a server-level rule rather than a per-plugin one, since the next plugin will make the same assumption. Block the archive extensions in the server configuration and include it in every virtual host.
3. The site loads, but PHP moved a major version
New hosts default to current PHP. Old sites frequently do not survive the jump, and the symptom is often a blank page rather than an error message.
What breaks is rarely the theme you are looking at. It is an abandoned plugin that has not been updated in four years, calling a function removed in PHP 8. Long-tolerated warnings become fatal errors.
First match the PHP version used on the old host and confirm the site works. Then upgrade with the debug log open. These are separate investigations: whether the move broke the site, and whether the PHP upgrade did. Combining them makes diagnosis harder.
If the result is a blank page rather than an error, the cause may not be PHP at all — we work through the four different mechanisms behind a blank WordPress page separately, and one of them is specific to migrations.
4. Mail stopped working and nobody noticed for weeks
Shared hosting almost always has a working local mail transfer agent. A fresh VPS image frequently does not. Nothing in WordPress tells you about the difference — wp_mail() returns false and the request moves on.
The consequence is invisible in exactly the way that hurts most: contact form notifications stop arriving, so it looks like enquiries dried up rather than like a broken server. Password resets stop working, which nobody discovers until someone is locked out. Order emails silently vanish.
One command on the new server settles whether the machine can send at all:
php -r 'var_dump( mail( "you@example.com", "post-migration test", "body" ) );'
which sendmail
bool(false) or no sendmail binary means the machine has no local mail transfer agent. That does not doom every fix — an SMTP or API-based plugin bypasses mail() and the local MTA entirely, which is exactly why it is a valid remedy. What it does mean is that anything relying on PHP’s mail() will keep failing until you either install an MTA or route around it deliberately.
One caveat on the test itself: PHP on the command line can use a different configuration from PHP under the web server. If the CLI check disagrees with what your forms do, trust the web-request behaviour. We cover the four layers this can fail at, and the two ways to fix the transport, in WordPress not sending emails.
Add one thing to your migration checklist that most people skip: submit the real contact form, from a browser, and confirm the message arrives in the real inbox. The plugin’s “send test email” button bypasses the form entirely and will pass on a site whose form is broken.
5. Cache drop-ins pointing at a server that no longer exists
Three files sit directly in wp-content/, load before almost everything, and never appear on the plugins screen: object-cache.php, advanced-cache.php and db.php.
An object-cache.php configured for a Redis instance the old host provided will take the new site down before WordPress finishes loading, and because it is not a plugin, deactivating plugins does not help and recovery mode does not pause it. The same blind spot covers mu-plugins/, which loads unconditionally on every request.
After any migration, look in those two places before anything else:
ls -la wp-content/object-cache.php wp-content/advanced-cache.php wp-content/db.php 2>/dev/null
ls -la wp-content/mu-plugins/
Rename anything that references a service the new server does not run. These files are the single most common reason a migrated site is blank while the database and files are provably intact.
6. The rewrite rule you wrote is not being read
This one costs hours because the evidence contradicts itself: the file on disk is correct, and the behaviour has not changed.
If the new server runs OpenLiteSpeed, it does not re-read .htaccess per request the way Apache does. You can write a perfectly valid rule, verify the file content, reload the page, and see nothing — until the server is restarted. LiteSpeed Enterprise is built for Apache compatibility and behaves much closer to Apache here, so advice written for one does not transfer to the other.
Before you conclude your redirect syntax is wrong, confirm which server you are actually on. Migrating from Apache to OpenLiteSpeed while carrying over Apache habits produces a specific kind of wasted afternoon.
7. It returns 200, but the feature is dead
A status code tells you less than a working feature. After migration, a page can show its header, footer and layout correctly while its main function has stopped working.
Product filters that return no products. Search that returns nothing. A form that shows a success message but submits nowhere. Pagination that 404s past page one. All of these return 200.
Test the function, not the response. Instead of checking that a category page loads, count the products in the response:
curl -s "https://example.com/product-category/widgets/"
| grep -o "product-item-class" | wc -l
Note the grep -o … | wc -l rather than grep -c: the latter counts matching lines, and minified HTML puts an entire product listing on one line.
Choose two or three checks per site that expose structural failures: a product count, a form message arriving in the inbox, and a page deep in pagination. These tell you more than the homepage, which is usually the most static page.
The same trap shows up in performance work, where every standard check can pass while the site stays slow — we work through what to look at once the checklist comes back green separately.
A post-migration checklist that assumes nothing
Ordered by how quietly each one fails, not by how likely it is:
- DNS actually points at the new server —
dig +short Aon both apex and www, compared against the new IP. Re-check a week later. - No archive left in the web root — search for archive extensions under
wp-content/, then try to download one from a public connection. Rotate credentials if it succeeds. - Cache drop-ins and mu-plugins reviewed — rename anything still pointing at old infrastructure. Copied files may still depend on the old host.
- The server can send mail — verified with a real form submission reaching a real inbox, not with a plugin’s test button.
- PHP version matched first, upgraded second — keep the debug log open and treat them as separate steps. That separates migration problems from upgrade problems.
- Function-level assertions pass — check product counts, form delivery and deep pagination. Test what the site does, as well as whether a page loads.
- The old host is decommissioned deliberately — only after the checks above, and only once you have confirmed traffic is arriving at the new server rather than assuming it.
- Uploads keep growing — check a month later. A frozen uploads directory on a supposedly live site means traffic is going somewhere else.
Item seven deserves emphasis in the other direction. Cancelling the old hosting the moment the new server responds is how the nine sites in the first section would have gone from “billed twice” to “offline”, because the old server was the one actually serving visitors. Keep the old host running until DNS is confirmed and traffic is visibly arriving at the new one.
We handle migrations and the cleanup afterwards as part of ongoing WordPress support, usually for export businesses whose sites need to stay reachable from both sides of the Great Firewall. If a site was moved recently and you want the checks above run against it, send us the URL.
