In this guide: 9 chapters
A migration has two jobs: copy the site exactly, and switch visitors over without anyone noticing. Most problems come from the second job. DNS changes too early, email breaks because the wrong records moved, or a store keeps taking orders on the old server after the copy was made.
This guide covers both jobs in order. Do the pre-flight checks a day or two ahead, copy and test the site while the old one stays live, and only then change DNS. Follow that order and your visitors never see a down site.
When to move, and the three ways to do it
People usually move for one of a few reasons. Watch for these signs:
- The site is slow even after caching and image work, and the server takes more than 0.8 seconds to answer.
- The bill keeps growing. Renewal prices jump, or visit caps push you onto a bigger plan every few months.
- Support is slow or scripted when the site is down.
- Missing basics, like staging, SSH access, daily off-site backups or a current PHP version.
- Repeat security problems that the host cannot explain or prevent.
Once you decide to move, there are three ways to do it.
| Method | Best for | Watch out for | Typical time |
|---|---|---|---|
| Migration plugin | Small and medium sites, owners who are not technical | Upload limits and timeouts on large sites. Free versions often cap the file size. | 1 to 3 hours |
| Manual copy | Large sites and developers with SSH access | Needs SSH or SFTP plus database access. Easy to miss a setting or break serialized data. | 2 to 6 hours |
| Done for you | Stores, busy owners and sites that cannot go down | Check what is included: testing, DNS, SSL and email. | Usually within a day |
Whatever the method, the steps around the copy stay the same: prepare, copy, test, switch and check. The rest of this guide walks through each one.
Start by finding out how big the site is. Size decides whether a plugin will cope or you need a manual copy:
du -sh wp-content
wp db size --human-readableOur free migration works from any host. We copy the site on the server side, test it on a temporary address, then switch it over with zero downtime, usually within a day.
You have picked a method, and you know the size of your files and database.
Before you move: the pre-flight checklist
A day or two before the move, collect everything you need and lower your DNS timers. This is the step people skip, and it is the one that prevents most surprises.
Take inventory
- Versions. WordPress, PHP and database versions, from Tools > Site Health > Info. Use the same or newer versions on the new host.
- DNS records. Every A, AAAA, CNAME, MX and TXT record, including SPF, DKIM, DMARC and any verification records. Export the zone file or take screenshots.
- Email. Is it on the old host, Google Workspace or Microsoft 365? Email hosted on the old server needs its own move.
- Scheduled tasks. Server cron jobs and anything that runs on a timer.
- SSL and CDN. Who issues the certificate, and is Cloudflare or another CDN in front of the site?
- Everything else in the web folder. Other apps, subdomains, staging copies, custom redirects in
.htaccessand custom PHP settings in.user.iniorphp.ini. - Services that trust your server IP. Payment gateways, APIs, email relays and firewalls that only accept requests from the old server.
dig +short example.com A
dig +short www.example.com CNAME
dig +short example.com MX
dig +short example.com TXT
# The second column of each answer is the TTL in seconds
dig +noall +answer example.com AGather the logins
Make sure you can sign in to everything before move day: the old host’s control panel, SFTP or SSH, the database, your domain registrar, your DNS provider (often Cloudflare or the registrar), and your email provider. Hunting for a password while the site is half moved is how moves stall. Store them in a password manager, never in a shared document.
Lower the TTL
The TTL (time to live) tells other servers how long to remember your DNS answer. Set it to 300 seconds on the A and CNAME records for your site, then wait for the old TTL to run out. If it was 86,400 seconds (one day), lower it at least a day before the move. On move day, the change then reaches almost everyone within five minutes.
Back up and plan the window
- Take a full backup of files and database, and test that it restores.
- Pick a quiet time based on your traffic. Early morning on a weekday works for most business sites.
- Tell anyone who edits the site to stop making changes from the final sync until the move is done. For a store, plan how you will handle orders during that window (see Chapter 6).
Do not cancel the old hosting yet. Keep it running until the new site has worked for 7 to 14 days and email is confirmed working.
You have a written list of every DNS record, the TTL on your site’s records shows 300, and you have a backup you have tested.
Copy the files and the database
A WordPress site is two things: files (mostly the wp-content folder plus wp-config.php) and a database. Copy both while the old site stays live.
With a migration plugin
Install the same plugin on both sites, export a package on the old site and import it on the new one. If the import fails partway, the package is usually too big for the plugin or the server limits. Switch to a manual copy rather than raising limits again and again.
By hand
- Copy the files. Use rsync over SSH if you can. It is fast, it can resume and it can run again later to copy only what changed. Skip cache folders, which the new server will rebuild.
- Export the database. Use
--single-transactionso the export stays consistent while the site is live. - Create a database and user on the new host, then import the export.
- Update the config file. Put the new database name, user, password and host in
wp-config.php. - Remove settings tied to the old host, such as its object cache file, must-use plugins and custom constants. Chapter 8 lists what to look for on popular hosts.
- Check file ownership and permissions. Files should belong to the site’s own account user. Our security guide covers the right permissions.
rsync -avz --exclude 'wp-content/cache/' --exclude 'wp-content/upgrade/' \
olduser@old-host.example.com:/home/olduser/public_html/ ./public_html/wp db export site.sql --single-transaction --quick
gzip site.sqlgunzip site.sql.gz
wp db import site.sql
wp cache flush
wp rewrite flushdefine( 'DB_NAME', 'new_database' );
define( 'DB_USER', 'new_user' );
define( 'DB_PASSWORD', 'use-a-new-strong-password' );
define( 'DB_HOST', 'localhost' );No WP-CLI on the old host? mysqldump does the same job: mysqldump --single-transaction --quick --default-character-set=utf8mb4 -u dbuser -p dbname > site.sql.
Large sites and multisite
Sites with tens of gigabytes of uploads or a database over 1 GB need a little more care. Copy uploads with rsync, which can pick up where it stopped if the connection drops. Import large databases from the command line, since browser tools such as phpMyAdmin time out. If the import fails with a “packet too large” error, ask your host to raise max_allowed_packet. Keep the utf8mb4 character set on both ends so emoji and special characters survive.
WordPress multisite networks are harder to move. Domains are stored in several network tables, and wp search-replace needs the --network flag. If you run a network with mapped domains, plan extra time for testing or have it done for you.
We copy sites server to server, so plugin size limits and timeouts do not apply, and we clean out the old host’s settings for you.
On the new server, these should all look right:
wp core verify-checksums passes, wp option get siteurl shows the correct address, and wp post list --post_type=any --format=count matches the old site.
Changing domains (skip if the domain stays the same)
If the site moves to a new domain, every stored link to the old domain has to change. WordPress stores some settings as serialized data, which records the length of each piece of text. Use a tool that understands it.
Never change the domain with a text editor or sed on the SQL file. If the old and new domains are different lengths, serialized settings break and widgets, theme options and page builder data quietly disappear.
wp search-replace handles serialized data correctly. Always run it with --dry-run first, and skip the guid column, which WordPress uses as a permanent ID for feeds and should never change:
# Preview the changes
wp search-replace 'https://old-domain.com' 'https://new-domain.com' --skip-columns=guid --dry-run
# Run it for real
wp search-replace 'https://old-domain.com' 'https://new-domain.com' --skip-columns=guid --report-changed-only
# Catch old http:// links too
wp search-replace 'http://old-domain.com' 'https://new-domain.com' --skip-columns=guid --report-changed-only
# Look for anything left (check the results by hand, this also matches email addresses)
wp search-replace 'old-domain.com' 'new-domain.com' --skip-columns=guid --dry-runThemes and custom code can hold the old domain too, where search-replace cannot reach. Search the files for it and change any matches by hand:
grep -rn "old-domain.com" wp-content/themes wp-content/mu-pluginsElementor keeps its own copies of some links. Run Elementor > Tools > Replace URL, then regenerate its CSS from the same screen.
Redirect the old domain
Send every old URL to the same path on the new domain with a permanent (301) redirect. Keep the old domain registered and redirecting for at least a year.
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www\.)?old-domain\.com$ [NC]
RewriteRule ^(.*)$ https://new-domain.com/$1 [R=301,L]Then tell Google. In Search Console, verify both domains and use the Change of Address tool on the old one.
The last dry run finds nothing that should change, and an old URL such as https://old-domain.com/about/ redirects with a 301 to https://new-domain.com/about/.
Test the new site before you switch DNS
Test the copy while the old site still serves every visitor. You can see the new server two ways: with a temporary address from your new host, or by pointing only your own computer at the new server with a hosts file entry. The hosts file is better, because the site runs on its real domain.
# macOS and Linux: /etc/hosts
# Windows: C:\Windows\System32\drivers\etc\hosts
203.0.113.10 example.com www.example.comReplace 203.0.113.10 with the new server’s IP address. Remove the line when you finish testing. To check from a terminal without touching the hosts file:
# -k skips the certificate check if SSL is not set up on the new server yet
curl -skI --resolve example.com:443:203.0.113.10 https://example.com/What to test
- The home page, your top landing pages and a few older posts.
- Images and downloads, including files linked from emails.
- Every form. Submit each one and confirm the email arrives.
- Logging in, the admin and any member or account pages.
- For stores: add to cart, coupons, checkout with a test payment, and the order emails.
- Search, redirects, the 404 page and the sitemap.
- Outgoing email from WordPress, such as password resets.
- Scheduled tasks, like backups, feeds and newsletters.
Check your top pages in one pass
Put the paths of your 20 or 30 most visited pages in a file called urls.txt, one per line, such as /about/. This loop requests each one from the new server and prints the status code. Every line should start with 200 (or 301 for pages you meant to redirect):
while read -r path; do
code=$(curl -sk -o /dev/null -w "%{http_code}" --resolve example.com:443:203.0.113.10 "https://example.com$path")
echo "$code $path"
done < urls.txtTests can touch real systems. A test order can trigger real shipping, and a form can email a real customer. Put payment gateways in test mode and use your own email address.
Every free migration is tested on a temporary address first. You get the link to check it yourself before anything changes.
Every item on the list works on the new server with the real domain, and you have compared a few pages side by side with the old site.
Switch DNS without downtime
With testing done and the TTL lowered, the switch takes minutes. The goal is that no visitor ever reaches a server that is down or out of date.
- Start the change freeze. Ask editors to stop publishing. For a store, choose your quietest hour.
- Do a final sync. Run rsync again to copy files that changed since the first copy, then export and import the database again so new posts, comments, users and orders come across.
- Point the site at the new server. Change the A record (and AAAA, if you use IPv6) to the new IP, and update the
wwwrecord if it points somewhere else. Leave MX and email TXT records alone unless email is moving too. - Make sure HTTPS works. Many hosts can only issue a free certificate once DNS points at them, so expect a few minutes of waiting. To avoid the gap, use DNS validation or, behind Cloudflare, an origin certificate set up in advance.
- Purge every cache on the new server and at your CDN.
- Put the old site in maintenance mode. Anyone whose DNS has not updated yet sees a short notice, so no orders or comments land on the old server. On a busy store, turn it on just before the final sync instead, so nothing changes on the old server after the copy.
- Watch the traffic move. The new server’s access log should fill up and the old one should go quiet within minutes.
dig +short example.com A @1.1.1.1
dig +short example.com A @8.8.8.8If you use Cloudflare with the orange cloud on, you change the IP in Cloudflare’s DNS and visitors switch almost at once, because Cloudflare answers for your domain and simply sends traffic to the new server.
Roll back if you need to
Keep the old site untouched until you are sure the move worked. If something serious breaks after the switch and you cannot fix it quickly, turn off maintenance mode on the old server and point the A record back to the old IP. With a 300 second TTL, visitors return to the old site within minutes. Fix the problem on the new server, then switch again.
We handle the final sync and DNS switch, leave email records untouched unless you ask us to move email, and have SSL ready before the switch.
Several public resolvers return the new IP, the site loads over HTTPS with a valid certificate, and the old server’s access log has gone quiet.
After the move: the first two weeks
Most post-move problems show up in the first few days. A short checklist catches them early.
In the first 48 hours
- Watch the PHP error log and the list of 404 errors, and fix any missing pages with redirects.
- Test forms, logins and checkout again on the live site.
- Confirm backups run on the new host and that scheduled tasks fire.
- Check that WordPress email still arrives. If the site sends mail directly, your SPF record may need the new server, or better, use an SMTP service.
- Update anything tied to the old IP address: payment gateway and API allowlists, uptime monitors and firewall rules.
Protect your search rankings
Staging copies are often set to “Discourage search engines from indexing this site”. If that setting comes along in the move, the site starts dropping out of Google. Check it first:
# 1 means search engines may index the site
wp option get blog_public
curl -s https://example.com/robots.txt
curl -sI https://example.com/sitemap_index.xml | head -1Then open Google Search Console, submit your sitemap and keep an eye on the Pages report for a few weeks. A short dip right after a move is normal. A steady slide usually points to blocked pages or missing redirects.
Check the speed
Run the same speed test you ran before the move on your key pages, and compare. The new server should be at least as fast. If it is slower, check that page caching is on, that the old host’s cache plugin is gone and that the CDN points at the new server. Our speed guide covers the full process.
Close out the old host
Keep the old hosting for 7 to 14 days. Before you cancel, download one last full backup and confirm no email, subdomain or other service still depends on it.
Our Indexing Keeper watches search engine visibility on every site we host, so a setting carried over from staging cannot quietly hide a live site from Google.
After a week, Search Console shows no new errors, blog_public is 1, backups run on the new host and you have a final backup from the old host.
Moving from WP Engine, Kinsta, GoDaddy or Bluehost
Big hosts add their own code and settings to WordPress. That code does nothing useful on a new server and can cause errors or block your new cache. After the copy, check the must-use plugins folder and wp-config.php for anything named after the old host.
wp plugin list --status=must-use
wp plugin list --status=dropin
ls -la wp-content/mu-pluginsWP Engine
WP Engine adds must-use plugins with names that start with wpengine or wpe, plus lines in wp-config.php that mention WP Engine. Remove them on the new server. Download your backup from the WP Engine User Portal. Our WP Engine migration page covers what changes when you move.
Kinsta
Kinsta adds a must-use plugin named kinsta-mu-plugins for its cache and tools. Remove it, along with any Kinsta-specific constants in wp-config.php. Our Kinsta migration page has the details.
GoDaddy and Bluehost
GoDaddy’s managed WordPress plans add a system plugin to the must-use folder, and Bluehost installs its own plugins. Remove both after the move. SSH access varies by plan on both hosts, so a migration plugin or a host-to-host move is often the easier route. Our GoDaddy and Bluehost migration page explains the move.
Features that stay behind
Some managed hosts include a CDN, a firewall, an image optimizer or a staging tool as part of the plan. These stop working the day you leave. List them before the move and plan a replacement for each one, such as your own Cloudflare account for the CDN and firewall.
We move sites from all of these hosts and remove their leftover plugins and settings as part of every free migration.
The must-use and drop-in lists show nothing from the old host, and the PHP error log stays clean after a day of traffic.
Do it yourself, or have it done
A small brochure site with SSH access is a good weekend project. Hand it off if the site takes orders or payments, has members, carries a large media library, shares the old host with your email, or you have no time to test properly.
| Task | Do it yourself | WP Farm free migration |
|---|---|---|
| Copy files and database | You | Our team, server to server |
| Remove old host settings | You | Our team |
| Test before the switch | You, with a hosts file | Our team, on a temporary address you can check |
| DNS switch and SSL | You | Our team, or we walk you through it |
| Email records | You | Left as they are, or moved with you |
| Cost | Your time | $0 with any hosting plan |
Questions to ask a new host
- Is the migration free, and does a person do it or do I use a plugin?
- Will I see the site on a temporary address before DNS changes?
- Who handles the DNS switch and SSL, and what happens to my email?
- How many days of backups are kept, and are they off-site?
- Can I get SSH, SFTP and staging on my plan?
- Is there a contract, and will you help me leave if it is not a fit?
Free migration comes with every plan, from any host, usually within a day. Try WP Farm for 60 days risk-free, and if it is not the right fit, we will help you move away for free.
You know which path fits your site, and you have a date for the move.
Written and reviewed by Nicky Stafford, founder of WP Farm. WP Farm has run managed WordPress hosting since 2008 and moves customer sites from other hosts as part of our free migration service. This guide follows the same steps our team uses.