A WordPress domain migration is not a copy. Copying files and a database to a new host under the same domain is a hosting move; changing the domain touches every stored address on the site, and there are thousands of them — in posts, in menus, in widget settings, in theme options, and in the serialized arrays that page builders save. This guide is the seven steps we use for a WordPress domain migration on client sites, in order, with the commands, the two traps that catch most people, and what to do about search rankings so the move does not cost you the traffic you built on the old name.
Before the WordPress domain migration: three decisions
Get these settled first, because each one changes the steps that follow.
| Decision | Options | Our default |
|---|---|---|
| Same host or new host? | Same server, new document root; or a fresh server | Same host if it is any good — one variable fewer |
| Scheme and www | https://example.com vs https://www.example.com | Pick one now; every rewrite below uses it |
| What happens to the old domain? | 301 to the new one, or let it lapse | Redirect for a year minimum; keep paying for it |
The scheme decision is the one people skip. A WordPress domain migration that rewrites http://old.com to https://new.com in one pass is clean; one that changes the domain now and the scheme next month does every step twice and leaves mixed-content warnings in between. Decide the final address, with its scheme and its www or not, and use exactly that string throughout.
The seven steps of a WordPress domain migration
1. Take a package you could restore from
Not a backup you hope works — one you have restored somewhere. If the move goes wrong at step four, this is the whole recovery plan. Files plus a complete database export, together, from the same moment:
A matched pair of files and database
# Database, with one row per line so it is easy to inspect
wp db export before-move.sql --skip-extended-insert
# Files (from the WordPress root)
tar -czf before-move-files.tgz --exclude='wp-content/cache' .
# On hosts where wp db fails (proc_open disabled), dump directly
mysqldump --defaults-file=~/.my.cnf dbname --skip-extended-insert > before-move.sqlWe do this step with Sitecarry, which produces one package with an installer and can rehearse the restore into scratch tables first; the six checks for a backup plugin explain why the rehearsal matters. Whatever you use, do not start a WordPress domain migration without a package you have proven.
2. Point DNS and get a certificate first
The new domain needs to resolve and serve HTTPS before WordPress lives there, or step five’s rewrite produces a site nobody can reach. Create the A or CNAME record, wait for it to resolve, and issue the certificate — Let’s Encrypt through the host panel is fine. Verify from outside:
Does the new name resolve and serve TLS?
dig +short new.com
curl -sI https://new.com | head -5
# Look for HTTP/2 200 or a redirect you understand, and no certificate errorDo this a day ahead if you can, because a WordPress domain migration waits on DNS more than on anything else. DNS caches on other people’s resolvers do not care about your schedule.
3. Put the files under the new domain
On the same host, this is usually adding the new domain in the panel and pointing its document root at the existing folder, or copying the folder to the new root. On a new host, upload the archive from step one and extract it. Either way, wp-config.php must now hold the right database credentials for wherever the database lives next.
Check file ownership and permissions after any copy. A WordPress domain migration that works but cannot upload images afterwards is almost always a permissions change on wp-content/uploads during the copy.
4. Import the database
If the database stays where it is, skip this. If it is moving too, create the new database, import, and confirm the table count matches:
Import and count
mysql --defaults-file=~/.my.cnf newdb < before-move.sql
mysql --defaults-file=~/.my.cnf newdb -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='newdb'"
# Compare with the same count on the sourceMismatched counts are the first real fault most people meet in a WordPress domain migration. They usually mean a plugin table with a name the import choked on, or an interrupted upload. Fix that before step five, because the rewrite will not run against tables that are not there.
5. Rewrite the old address everywhere, safely
This is the step that defines a WordPress domain migration, and the one where the tool matters. The old address appears in siteurl and home, in post content, in menu items, in widgets, in theme and plugin options — and a large share of those are stored serialized. A serialized string carries its own length: s:19:"https://old.com/abc". Replace the domain with a longer or shorter one in a plain text editor or a naive SQL REPLACE(), and the length is wrong; PHP fails to unserialize the value; the setting reads as empty. Elementor layouts are the usual casualty, because their data is one large serialized array per page.
The right tool: serialization-aware replace
# Dry run first — count what would change, table by table
wp search-replace 'https://old.com' 'https://new.com' --all-tables --dry-run
# Then for real, with a report
wp search-replace 'https://old.com' 'https://new.com' --all-tables --report-changed-only
# Also catch the scheme-less and escaped forms page builders store
wp search-replace '//old.com' '//new.com' --all-tables --report-changed-only
wp search-replace 'https:\/\/old.com' 'https:\/\/new.com' --all-tables --report-changed-onlywp search-replace unserializes, replaces, and re-serializes with corrected lengths. It is pure PHP, so it works even on hosts that disable proc_open. The third command matters for Elementor and similar builders, which store JSON inside the serialized data with escaped slashes; a WordPress domain migration that skips it leaves images pointing at the old domain inside every builder page.
Without WP-CLI, use a tool that does the same job through a browser — Sitecarry’s installer does it as part of the restore, and the standalone Search Replace DB script does it on its own. Do not use phpMyAdmin’s find-and-replace for this; it is the naive kind.
6. Flush everything that remembers the old domain
Four things cache the old address and each one produces a different “the migration did not work” report:
| Cache | Symptom | Flush |
|---|---|---|
| Rewrite rules | Every page except the front 404s | wp rewrite flush, or save Settings › Permalinks |
| Object cache | Site still “thinks” it is old.com | wp cache flush |
| Page cache and CDN | Old HTML with old links served to visitors | Purge in the plugin and at the CDN |
| Page-builder CSS | Background images missing on builder pages | Elementor › Tools › Regenerate CSS, or wp elementor flush-css |
The browser is a fifth cache. Test the new domain in a private window; a normal one may be following a redirect it cached last week, which is the same trap that hides Elementor changes.
7. Redirect the old domain, permanently
Rankings, backlinks and bookmarks all point at the old name. A 301 from every old URL to its exact new equivalent moves them; a redirect to the new home page throws most of them away. On the old domain’s server, one rule does it:
.htaccess on the old domain (Apache / LiteSpeed)
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?old\.com$ [NC]
RewriteRule ^(.*)$ https://new.com/$1 [R=301,L]Then tell Google. Search Console’s Change of Address tool exists for exactly this; use it after the redirects are live, not before. Keep the old domain registered and redirecting for at least a year — the guide to redirects that keep rankings covers the rest, and why a site drops out of Google is what happens when this step is skipped.
Checking the WordPress domain migration worked
Do these before announcing anything. Each takes a minute and each catches a real class of failure.
Five checks from the command line
# 1. Nothing still says old.com in the database
wp search-replace 'old.com' 'new.com' --all-tables --dry-run
# → should report 0 replacements
# 2. The site knows its own address
wp option get siteurl && wp option get home
# 3. A deep URL, an image and the feed all answer 200 on the new domain
curl -sI https://new.com/blog/some-post/ | head -1
curl -sI https://new.com/wp-content/uploads/2026/01/hero.jpg | head -1
curl -sI https://new.com/feed/ | head -1
# 4. The old domain redirects, once, with a 301, to the matching path
curl -sI https://old.com/blog/some-post/ | grep -i "^HTTP\|^location"
# 5. No mixed content: nothing on the page loads over http
curl -s https://new.com/ | grep -c 'http://old.com'Then log in, open the media library, upload one image, and edit one builder page. Uploads test permissions; the builder page tests that step five reached the serialized data. If the browser shows a mixed-content warning, check five found a hard-coded http:// the rewrite did not cover.
Free tools for a WordPress domain migration, compared
| Tool | Handles serialized data | Free limits | Best for |
|---|---|---|---|
WP-CLI search-replace | Yes | None; needs SSH | Anyone with a terminal |
| Sitecarry | Yes, in the installer | None; files + database, S3 / FTP / Drive | Moves without SSH; the same package is the backup |
| Duplicator | Yes, in the installer | Large sites and scheduling are paid | Small sites, one-off moves |
| All-in-One WP Migration | Yes | The free version caps import size | Small sites through the browser |
| Host migration tools | Usually | Only into that host | Moving to that host anyway |
Honestly: Duplicator is the one most people know, and for a small site it is fine. Its free version struggles with large uploads and multi-gigabyte packages, which is where hosting moves usually hurt. We built Sitecarry because our own WordPress domain migration jobs kept hitting those limits and because none of the free tools would prove a package restores before the day it has to. If you have SSH, WP-CLI alone is enough for the rewrite and costs nothing; the hosting-move guide walks the same route when the domain stays put.
A WordPress domain migration without SSH
Most shared hosting gives you a panel, a file manager and phpMyAdmin, and no terminal. The seven steps do not change; the tools do. This is the same WordPress domain migration done through a browser, and the two places it needs more care.
Steps one, three and four collapse into one when you use a package tool. Sitecarry builds the package from the old site’s admin and gives you two files: the archive and installer.php. Upload both to the new domain’s document root with the file manager, open https://new.com/installer.php, and give it the new database name, user and password. It extracts the files, imports the database in resumable slices — which is what keeps a large site inside the host’s 30-second request limit — and then asks for the new URL. That last screen is step five: it runs the serialization-aware rewrite across every table, including the escaped-slash form that page builders store, and shows a count of what changed.
The care points are the database size and the cache. phpMyAdmin imports are capped by the host’s upload limit, often 50 MB, so a database larger than that has to go through a package tool or be split; a WordPress domain migration that stalls at “import” nearly always hit that cap. And with no terminal, step six is buttons: Settings › Permalinks › Save flushes rewrite rules, the cache plugin’s purge button clears pages, and Elementor › Tools › Regenerate CSS rebuilds the stylesheets. Do all three, in that order, before testing.
Step seven still needs the old domain’s .htaccess. Every panel file manager can edit it; the rule is the same three lines as above. If the old hosting account is being closed, set the redirect at the registrar or DNS provider instead — most offer a URL forward with a 301 option, and it does not preserve paths unless it says so, so look for “forward with path”.
Where a WordPress domain migration goes wrong
| Mistake | What you see | Fix |
|---|---|---|
Plain SQL REPLACE() on the old domain | Builder pages blank; theme options reset | Restore step one; redo with wp search-replace |
| Rewriting before DNS and TLS are ready | Site unreachable; admin redirects to nowhere | Set WP_HOME/WP_SITEURL back in wp-config until DNS resolves |
| Redirecting everything to the new home page | Rankings for deep pages vanish within weeks | Path-preserving 301 per URL |
| Forgetting the escaped-slash form | Images missing inside Elementor pages only | The third search-replace in step five |
| Letting the old domain lapse | Someone else registers it; your backlinks now point at them | Renew for years, not months |
| Hard-coded URLs in wp-config or the theme | One stubborn old.com link the database rewrite cannot reach | grep -rn "old.com" wp-config.php wp-content/themes/ |
The second row has a fast recovery worth memorising. If a WordPress domain migration leaves you locked out because the URLs changed before the domain worked, two lines in wp-config.php override the database until you sort it out:
Emergency override
define( 'WP_HOME', 'https://old.com' );
define( 'WP_SITEURL', 'https://old.com' );Remove them when the new domain resolves; the locked-out guide has the other routes back in. Keep the package from step one until the WordPress domain migration has been live for a month — it is the only complete record of the site as it was.
Questions about WordPress domain migration
Will a WordPress domain migration hurt my Google rankings?
Temporarily, a little; permanently, only if the redirects are wrong. With path-preserving 301s from every old URL, a Change of Address in Search Console, and the old domain kept alive, most sites see a dip of a few weeks and then recover. Redirecting everything to the home page, or letting the old domain lapse, is what causes the lasting losses.
Can I do a WordPress domain migration without SSH?
Yes. A package-and-installer tool does the file copy, the database import and the serialization-aware rewrite from a browser. The steps are the same; the commands are buttons. What you lose is the dry-run counts, so check the builder pages by eye afterwards.
How long does the move take?
Steps one to six, for a typical business site, take under an hour once DNS is ready. DNS and the certificate can take a day ahead of that. The redirect step lasts a year, which is not the same as taking a year.
Do I need to change anything in Elementor after the move?
Run Elementor › Tools › Regenerate CSS after the rewrite, because the generated stylesheets contain image URLs. If backgrounds are still missing, the escaped-slash form of the old domain was not replaced; run the third command from step five.
What about email addresses on the old domain?
A WordPress domain migration does not move mailboxes; those live with whoever hosts the email. Set up the new addresses first, add them to the site’s sending settings, and forward the old ones for as long as the old domain lives. The emails-not-sending guide covers the SPF and DKIM records the new domain will need.
Should I move the host at the same time?
Only if you have to. Two changes at once doubles the places a fault can hide. If the host must change, do the hosting move under the old domain first, confirm it, then the domain change — or use a package tool that treats both as one restore with one rewrite.
Can I test the WordPress domain migration before switching?
Yes, by restoring the package to the new domain while the old site stays live, checking everything, and only then adding the redirects. Nothing on the old site changes until step seven. That is the safest order and the one we use.
