How to move a WordPress site to a new host

Copy the files and database, test on the new server before anyone else sees it, then switch DNS with the old host kept as your way back.

4–6 minutes
Assorted laptop and desktop hard drives

A WordPress site is two things: a folder of files and a MySQL or MariaDB database. Moving it means copying both, connecting them, testing, and only then pointing the domain at the new server. Done in that order, visitors never see a broken site and the old host stays as your way back.

You need: SSH or file access to both servers, an empty database and user on the new server, and access to your DNS. This guide uses WP-CLI; each step notes the alternative.

Choose your method

MethodBest forWatch out for
WP-CLI over SSH (this guide)Any size, full controlNeeds SSH on both servers
Migration pluginNo SSH access, small to medium sitesUpload limits and timeouts on large sites; check the free tier’s size cap
Host’s free migration serviceNot wanting to do it yourselfTiming is on their schedule; check what they include
cPanel to cPanel transferBoth hosts use cPanelMoves the whole account; see cPanel to cPanel

The steps below are the same ones a plugin performs behind the scenes, so they are worth knowing even if you use a plugin.

1. Lower the DNS TTL a day early

Set your domain’s A record TTL to 300 seconds at least as long before the move as the current TTL. When you switch later, the change spreads in minutes. See DNS propagation.

2. Export the database and pack the files

On the old server, in the folder that contains wp-config.php:

wp db export ~/site.sql
tar czf ~/site-files.tar.gz -C "$(pwd)" .

Without WP-CLI, use mysqldump -u DB_USER -p DB_NAME > ~/site.sql with the values from wp-config.php, or phpMyAdmin’s Export tab. From now until the move is done, avoid publishing or changing content.

3. Copy both to the new server

From the new server:

scp olduser@old.server.ip:~/site.sql olduser@old.server.ip:~/site-files.tar.gz ~/
tar xzf ~/site-files.tar.gz -C /var/www/example.com/public

4. Connect WordPress to the new database

cd /var/www/example.com/public
wp config set DB_NAME new_db_name
wp config set DB_USER new_db_user
wp config set DB_PASSWORD 'new-db-password'
wp db import ~/site.sql
sudo chown -R www-data:www-data /var/www/example.com/public

www-data is the web server user on Debian and Ubuntu; use your server’s.

Changing the domain too? WordPress stores full URLs in the database, some inside serialized data that plain find-and-replace corrupts. Use WP-CLI, with --dry-run first:

wp search-replace 'https://old-domain.com' 'https://new-domain.com' --skip-columns=guid --dry-run

5. Test before anyone else sees it

Point the domain at the new server for your computer only by adding a line to your hosts file (/etc/hosts on macOS and Linux, C:\Windows\System32\drivers\etc\hosts on Windows):

203.0.113.10  example.com www.example.com

Flush your DNS cache, then log in, open posts, submit a form and check images. Expect a certificate warning until the new server has one. Remove the line when finished.

6. Switch DNS and add the certificate

Change the A record (and AAAA) to the new IP. Once dig example.com +short shows it, issue a certificate. See free SSL with Let’s Encrypt.

Leave the MX records alone unless you are moving email too.

Checks after the switch

Work through these on the live site once DNS has moved:

  • Home page, a post, a page and a category archive all load.
  • Settings > Permalinks > Save once, to rebuild rewrite rules on the new server.
  • Images and downloads load, including older uploads.
  • Contact forms send email, and the email arrives (not in spam).
  • Logging in and out works, and the admin area is fast.
  • Scheduled tasks run. WordPress’s own cron needs visitors or a real cron job; on a new server, add */5 * * * * cd /var/www/example.com/public && wp cron event run --due-now >/dev/null 2>&1 to the site user’s crontab and set define( 'DISABLE_WP_CRON', true ); in wp-config.php.
  • Caching and security plugins are reconfigured; some store server paths.
  • Backups are scheduled on the new host.
  • The site shows a padlock with no mixed-content warnings.

Common problems after a move

SymptomCauseFix
Home page works, every other page is 404Rewrite rules not set on the new server404 fix, step 1
Error establishing a database connectionWrong database details in wp-config.phpDatabase connection fix
White screen or critical errorMissing PHP extension, or a different PHP versionWhite screen fix
Redirects to the old domain or a loophome and siteurl options, or HTTPS settingsToo many redirects
Images missingUploads not copied, or old absolute URLsCopy wp-content/uploads, then run wp search-replace
Padlock missing, “not secure”Certificate not issued yet, or http:// links in contentIssue the certificate, then search-replace http:// to https://
Upload fails with “unable to create directory”File ownershipRe-run the chown from step 4

7. Keep the old host for a few days

Some visitors reach the old server until their resolvers catch up. Keep it running for at least 72 hours and check it for comments, orders or form entries that arrived during the switch. Then take a final backup, cancel it, and set the TTL back to 3600.

Large sites

For sites with tens of gigabytes of uploads, copying one big archive is slow and fragile. Copy uploads directly with rsync, which can resume and only copies what changed:

rsync -avz --progress olduser@old.server.ip:/var/www/example.com/public/wp-content/uploads/ /var/www/example.com/public/wp-content/uploads/

Run it once in advance, then again just before the switch to pick up new files. For large databases, compress the export as you create it with wp db export - | gzip > ~/site.sql.gz, and import with gunzip < ~/site.sql.gz | wp db import -.

Something out of date? Software changes. If a step no longer works, tell us and we will check it and update the page.