
In this article
Most broken WordPress migrations come down to four things: the database still contains the old URL, the web server is not routing pretty permalinks, HTTPS is detected wrongly behind a proxy or CDN, or wp-config.php points at the wrong database. Each has a quick, reliable fix, and WP-CLI handles the hardest one, rewriting URLs inside serialized data, safely.
This guide starts with a symptom table so you can jump to your problem, then walks through each fix in the order you should try them. Commands are from the current WP-CLI reference and the WordPress Advanced Administration Handbook.
Find your symptom
| Symptom after the move | Most likely cause | Go to |
|---|---|---|
| "Error establishing a database connection" | Wrong database name, user, password or host in wp-config.php | Fix 1 |
| Site redirects to the old domain, or admin links point there | home and siteurl still hold the old URL | Fix 2 |
| Images missing, mixed-content warnings, links to the old domain in posts | Old URLs stored in content, meta and options | Fix 3 |
| "Too many redirects" after switching to HTTPS | WordPress cannot see HTTPS behind a proxy or CDN | Fix 4 |
| Home page works, every other page returns 404 | Rewrite rules or web server config not in place | Fix 5 |
| White screen or "There has been a critical error" | PHP version, a plugin, or memory limits on the new server | Fix 6 |
Before changing anything, take a fresh database export on the new server, so every fix below can be undone:
wp db export before-fixes.sqlFix 1: "Error establishing a database connection"
The handbook's first suspect is wp-config.php. Check DB_NAME, DB_USER, DB_PASSWORD and DB_HOST against what the new host gave you. DB_HOST is the usual culprit: many hosts use a separate database server name rather than localhost, and some need a port or socket.
# Shows the values WordPress will use, read from wp-config.php
wp config get DB_HOST
wp config get DB_NAME
# Confirms WP-CLI can reach and check the database
wp db checkIf the table prefix changed between servers, $table_prefix in wp-config.php must match the imported tables, or WordPress will behave as if it is not installed.
Fix 2: The site keeps sending you to the old domain
WordPress stores its own address in two options: home (the public address) and siteurl (where the core files live). Check them first:
wp option get home
wp option get siteurl
wp option update home 'https://new-example.com'
wp option update siteurl 'https://new-example.com'If the values look right but the site still redirects, look for WP_HOME and WP_SITEURL constants in wp-config.php. They override the database, which is useful when you cannot reach wp-admin, but easy to forget.
define( 'WP_HOME', 'https://new-example.com' );
define( 'WP_SITEURL', 'https://new-example.com' );The handbook also describes a
RELOCATEconstant that updates the site URL from the login screen. If you use it, remove it immediately afterwards: leaving it in place lets an attacker change your site URL in some configurations.

Fix 3: Old URLs in content, images and settings
Changing home and siteurl does not touch the old address embedded in post content, image URLs, widget settings and plugin options. You need a search and replace across the database, and it must not be done with a text editor or sed on the SQL dump.
Why a plain find-and-replace breaks sites
Many themes, widgets and plugins store settings as PHP serialized data, which records the length of each string:
s:24:"https://old-example.com/";Replace the domain with one of a different length and the stored length no longer matches. PHP then fails to unserialize the value and the setting silently disappears. WP-CLI's search-replace handles serialized data correctly and never changes primary keys.
Run it safely
# 1. Preview: counts replacements per table without saving anything
wp search-replace 'https://old-example.com' 'https://new-example.com' \
--skip-columns=guid --dry-run
# 2. Run it for real
wp search-replace 'https://old-example.com' 'https://new-example.com' \
--skip-columns=guid
# 3. Catch leftover http:// links from before the site used HTTPS
wp search-replace 'http://old-example.com' 'https://new-example.com' \
--skip-columns=guidNotes on the options:
--skip-columns=guid: the handbook is emphatic that theguidcolumn in the posts table must never change. Feed readers use it to recognise posts they have already shown.- Tables: by default only tables registered with WordPress are searched. Add
--all-tables-with-prefixfor plugin tables that use your prefix but are not registered. --preciseforces PHP processing for every column. It is slower but more reliable for complex serialized structures.--export=fixed.sqlwrites the transformed data to a file instead of the database, if you prefer to review first.
Search for the bare domain afterwards (for example old-example.com with --dry-run) to find protocol-relative or unusual references, and review those before replacing them.
Fix 4: "Too many redirects" after enabling HTTPS
When a load balancer, reverse proxy or CDN terminates TLS and talks to WordPress over plain HTTP, WordPress thinks every request is insecure and keeps redirecting to HTTPS. The HTTPS handbook page describes the fix: trust the proxy's X-Forwarded-Proto header in wp-config.php, above the "stop editing" line.
define( 'FORCE_SSL_ADMIN', true );
// Only add this when your proxy or CDN sets the header and clients cannot reach PHP directly.
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && false !== strpos( $_SERVER['HTTP_X_FORWARDED_PROTO'], 'https' ) ) {
$_SERVER['HTTPS'] = 'on';
}Also check your CDN's TLS mode. If the CDN connects to the origin over HTTP while the origin forces HTTPS, the two will bounce requests between them forever. Use a mode that connects to the origin over HTTPS with a valid certificate.
Fix 5: Every page except the home page is a 404
Pretty permalinks depend on the web server sending unknown paths to index.php. After a move, the rules are often missing.
# Regenerate rewrite rules; --hard also rewrites .htaccess (Apache, single site only)
wp rewrite flush --hardOn Apache, confirm that mod_rewrite is enabled and that .htaccess contains the standard WordPress block. On Nginx, .htaccess is ignored; the server block needs a location / rule with try_files $uri $uri/ /index.php?$args;. If only custom post types return 404, make sure no page shares a slug with the post type and flush the rules again.

Fix 6: White screen or critical error
A new server often means a different PHP version, memory limit or set of extensions. Turn on logging without showing errors to visitors:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );Reload the page and read wp-content/debug.log. If a plugin is to blame, WP-CLI can still run with plugins skipped, which lets you deactivate the culprit:
wp plugin list --status=active --skip-plugins
wp plugin deactivate problem-plugin --skip-pluginsTurn WP_DEBUG off again when you are done.
Gotchas
- Persistent object caches remember old values. If Redis or Memcached was copied or shared, run
wp cache flushafter any URL change. - Page caches and CDNs keep serving old HTML. Purge them after the search and replace, not before.
- Hard-coded URLs live outside the database too. Check theme files, custom CSS and
wp-config.phpfor the old domain. - Multisite is different. URLs are stored in each site's tables and in
wp_blogsandwp_site. Use--networkwith--urlto target the network, and follow the multisite moving guide. - Uploads must be copied separately. The database only stores paths; missing images after a correct search and replace usually mean
wp-content/uploadswas not copied or has the wrong ownership.
Post-migration checklist
wp option get homeandsiteurlshow the new HTTPS address.wp search-replace 'old-example.com' 'new-example.com' --dry-run --skip-columns=guidreports zero matches you did not intend to keep.- Home, a post, a page, a category archive, search and a custom post type all load.
- You can log in, save a post and upload an image.
- Caches are purged and Site Health shows no new critical issues.
- Debug logging is off and any
RELOCATEconstant is removed. - Redirects from the old domain to the new one return 301 for every path.
Frequently asked questions
Can I use sed or a text editor to change URLs in a WordPress SQL dump?
Not safely. Serialized PHP data stores string lengths, so changing a URL's length corrupts those values. Use
wp search-replace, which unserializes, replaces and reserializes the data.Should I replace URLs in the guid column?
No. The handbook says the
guidcolumn must never change, because feed readers use it to identify posts. Add--skip-columns=guidto everysearch-replacerun.What is the difference between home and siteurl?
homeis the address visitors use for your site.siteurlis where the WordPress core files are installed. They are usually the same unless WordPress lives in a subdirectory.Why does wp rewrite flush --hard not fix my 404s on Nginx?
The
--hardoption writes.htaccess, which only Apache reads. On Nginx, addtry_files $uri $uri/ /index.php?$args;to thelocation /block of your server configuration.How do I log in if the site redirects to the old domain?
Use WP-CLI to run
wp option update homeandwp option update siteurl, or temporarily defineWP_HOMEandWP_SITEURLinwp-config.php.How do I preview a search and replace before running it?
Add
--dry-run. WP-CLI runs the whole operation and reports the number of replacements per table without saving anything.
Your next customer could start right here.
Introduce your tool, product or business to readers exploring technology.
Explore placements and request a private quote
Sources
- Migrating WordPress — WordPress Advanced Administration Handbook
- wp search-replace — WP-CLI Command Reference
- Common WordPress errors — WordPress Advanced Administration Handbook
- HTTPS — WordPress Advanced Administration Handbook
- wp rewrite flush — WP-CLI Command Reference
- Nginx — WordPress Advanced Administration Handbook
Written with substantial AI assistance. Facts checked against cited sources. Editorial policy.
Comments
No comments yet. Be the first to join the conversation.
Leave a comment
Every comment is read by a moderator before it appears. Your email address is never published; it is used only to contact you about this comment.
More from Cloudsoft Zone

Resource guideWordPress
WordPress security hardening checklist for 2026 (WordPress 7.1)
A practical WordPress 7.1 hardening checklist based on the official handbook: updates, two-step logins, wp-config.php constants, file permissions, database privileges, firewalls, WP-CLI checksum checks and tested backups.
By Cloudsoft Zone

TutorialWordPress
How to update WordPress safely with WP-CLI: backup, update, verify, roll back
A repeatable WordPress update routine with WP-CLI: check pending updates, export the database and archive files, update core, plugins, themes and translations in order, verify checksums, and restore if something breaks.
By Cloudsoft Zone

Troubleshooting guideCodeIgniter
CodeIgniter 4 validation not working? 9 causes and fixes
Fix CodeIgniter 4 validation problems fast: wrong input source, lost errors after redirect, permit_empty, strict JSON rules, is_unique placeholders and more.
By Cloudsoft Zone
