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
| Method | Best for | Watch out for |
|---|---|---|
| WP-CLI over SSH (this guide) | Any size, full control | Needs SSH on both servers |
| Migration plugin | No SSH access, small to medium sites | Upload limits and timeouts on large sites; check the free tier’s size cap |
| Host’s free migration service | Not wanting to do it yourself | Timing is on their schedule; check what they include |
| cPanel to cPanel transfer | Both hosts use cPanel | Moves 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>&1to the site user’s crontab and setdefine( 'DISABLE_WP_CRON', true );inwp-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
| Symptom | Cause | Fix |
|---|---|---|
| Home page works, every other page is 404 | Rewrite rules not set on the new server | 404 fix, step 1 |
| Error establishing a database connection | Wrong database details in wp-config.php | Database connection fix |
| White screen or critical error | Missing PHP extension, or a different PHP version | White screen fix |
| Redirects to the old domain or a loop | home and siteurl options, or HTTPS settings | Too many redirects |
| Images missing | Uploads not copied, or old absolute URLs | Copy wp-content/uploads, then run wp search-replace |
| Padlock missing, “not secure” | Certificate not issued yet, or http:// links in content | Issue the certificate, then search-replace http:// to https:// |
| Upload fails with “unable to create directory” | File ownership | Re-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 -.
Related
Something out of date? Software changes. If a step no longer works, tell us and we will check it and update the page.

