Maintenance

WordPress Domain Migration: 7 Simple Steps, Done Free

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.

DecisionOptionsOur default
Same host or new host?Same server, new document root; or a fresh serverSame host if it is any good — one variable fewer
Scheme and wwwhttps://example.com vs https://www.example.comPick one now; every rewrite below uses it
What happens to the old domain?301 to the new one, or let it lapseRedirect 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.sql

We 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 error

Do 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 source

Mismatched 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-only

wp 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:

CacheSymptomFlush
Rewrite rulesEvery page except the front 404swp rewrite flush, or save Settings › Permalinks
Object cacheSite still “thinks” it is old.comwp cache flush
Page cache and CDNOld HTML with old links served to visitorsPurge in the plugin and at the CDN
Page-builder CSSBackground images missing on builder pagesElementor › 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

ToolHandles serialized dataFree limitsBest for
WP-CLI search-replaceYesNone; needs SSHAnyone with a terminal
SitecarryYes, in the installerNone; files + database, S3 / FTP / DriveMoves without SSH; the same package is the backup
DuplicatorYes, in the installerLarge sites and scheduling are paidSmall sites, one-off moves
All-in-One WP MigrationYesThe free version caps import sizeSmall sites through the browser
Host migration toolsUsuallyOnly into that hostMoving 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

MistakeWhat you seeFix
Plain SQL REPLACE() on the old domainBuilder pages blank; theme options resetRestore step one; redo with wp search-replace
Rewriting before DNS and TLS are readySite unreachable; admin redirects to nowhereSet WP_HOME/WP_SITEURL back in wp-config until DNS resolves
Redirecting everything to the new home pageRankings for deep pages vanish within weeksPath-preserving 301 per URL
Forgetting the escaped-slash formImages missing inside Elementor pages onlyThe third search-replace in step five
Letting the old domain lapseSomeone else registers it; your backlinks now point at themRenew for years, not months
Hard-coded URLs in wp-config or the themeOne stubborn old.com link the database rewrite cannot reachgrep -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.