By the end, the reader will have a fully working copy of a WordPress site running on a new server — database imported, wp-config.php pointed at the new credentials, site URLs corrected where the domain or protocol changed — verified locally and then cut over via DNS with minimal downtime.
Prerequisites
A source Ubuntu 22.04 LTS server currently running the WordPress site, reachable over SSH as a sudo user
A destination Ubuntu 22.04 LTS server with a web server (Apache or Nginx), PHP, and MySQL or MariaDB already installed, with a virtual host or server block configured for the domain
SSH access to both servers, and the ability to transfer files directly between them (or via your local machine)
The current site's database name, database username, and database password (found in wp-config.php)
Sudo or root access to MySQL/MariaDB on both servers
Access to the domain's DNS records through its registrar or DNS provider
Enough free disk space on both servers to hold a full copy of the site files and a database dump
Let an AI agent do this for you
Copy a ready-made prompt for an AI coding assistant with terminal access to your server (Claude Code, Cursor, or similar) — it can carry out the steps below for you. Review what it plans to run before it executes anything.
Migrating a WordPress site to a new server means moving two things that must stay in sync: the MySQL/MariaDB database (posts, pages, users, settings, plugin data) and the filesystem (WordPress core, themes, plugins, and uploaded media in wp-content). Get one without the other and the site either loads with no content or fails to connect to a database at all. This tutorial walks through exporting the database, archiving the site files, transferring both to a new server, re-importing them, updating the database credentials WordPress uses to connect, rewriting the site URL when the domain or protocol changes, and verifying everything works before you point DNS at the new server.
The steps below assume a source Ubuntu 22.04 LTS server currently running the WordPress site and a destination Ubuntu 22.04 LTS server with a web server, PHP, and MySQL or MariaDB already installed. If the destination server has no LAMP/LEMP stack yet, install and configure that first — this guide covers only the migration itself, not the initial stack setup.
Step 1 — Assess the Current Site and Lower the DNS TTL
Before touching any files, confirm where the WordPress installation actually lives on the source server. For a site served by Apache or Nginx from a virtual host, this is commonly a directory such as /var/www/example.com or /var/www/html. Confirm the path, and note the database name, database username, and database password currently in wp-config.php — you will need all three later, and you will need the first two again (with new credentials) on the destination server.
If this migration will change which server the domain's DNS points to, lower the Time To Live (TTL) on the domain's DNS records well ahead of the cutover — ideally 24 to 48 hours in advance — through your DNS provider's control panel. A short TTL (for example, 300 seconds) means that when you eventually update the A record to the new server's IP address, resolvers worldwide pick up the change quickly instead of continuing to serve the old address for hours. You can check the current TTL with dig:
bash
dig example.com +noall +answer
“Lowering the TTL does not move any traffic yet — it only shortens how long the eventual DNS change takes to propagate. Do this early, then wait for the old, longer TTL to fully expire before proceeding with the cutover in Step 10.”
Step 2 — Export the WordPress Database on the Source Server
Use mysqldump to export the database to a single .sql file. Run this on the source server, using the database credentials found in wp-config.php:
Tricknowtech VPS Hosting
Dedicated KVM resources and full root access — deployed in under 60 seconds, no ticket required.
--single-transaction takes a consistent snapshot without locking InnoDB tables for the duration of the dump, so the site can keep serving requests while you export.
--quick streams rows instead of buffering the whole result set in memory, which matters on large tables like wp_postmeta or wp_options.
--lock-tables=false avoids table locks, useful on shared or busy databases; omit it if you specifically want a locked, fully static snapshot instead.
For a large database, compress the dump as it's written to save transfer time and disk space:
Archive the entire WordPress directory with tar so file permissions, hidden files (like .htaccess), and the full directory structure are preserved in one file. Run this from the parent of the site directory, still on the source server:
bash
cd /var/www
sudo tar -czvf wordpress-site.tar.gz example.com
This captures wp-admin, wp-includes, wp-config.php, and wp-content (themes, plugins, and uploads) in a single compressed archive named wordpress-site.tar.gz. If the destination server will instead get a fresh WordPress core install via its package manager or WP-CLI, and only the customized parts of the site need to move, archive just wp-content and wp-config.php instead:
bash
cd /var/www/example.com
sudo tar -czvf wp-content-backup.tar.gz wp-content wp-config.php
“The wp-content directory typically contains the bulk of the data — especially uploads/ — so confirm you have enough free disk space on the source server for the archive before running tar. Check with df -h .”
Step 4 — Transfer the Archive and Database Dump to the New Server
Copy both files to the destination server. scp is simplest for a one-time transfer; rsync is preferable for large sites because it shows progress and can resume an interrupted transfer. Either works over the same SSH connection you already use to manage the servers.
Replace sammy with the sudo user on the destination server and 203.0.113.10 with its actual IP address. If rsync isn't installed on the source server, install it first with sudo apt install rsync.
Step 5 — Prepare the Database and Extract the Files on the New Server
On the destination server, log in to MySQL or MariaDB as an administrative user and create a new, empty database along with a dedicated user for WordPress to connect with:
bash
sudo mysql -u root -p
sql
CREATE DATABASE wordpress_db;
CREATE USER 'wordpress_user'@'localhost' IDENTIFIED BY 'REPLACE_WITH_A_STRONG_PASSWORD';
GRANT ALL PRIVILEGES ON wordpress_db.* TO 'wordpress_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
You can reuse the same database name and username as the source server, or choose new ones — either way, use a new, strong password rather than reusing the old one. Next, extract the file archive into the web root:
bash
cd /var/www
sudo tar -xzvf /home/sammy/wordpress-site.tar.gz
sudo chown -R www-data:www-data /var/www/example.com
Adjust www-data if the web server on the destination runs as a different user, and make sure a virtual host (Apache) or server block (Nginx) already points at /var/www/example.com before continuing.
Step 6 — Import the Database
Decompress the dump if you gzipped it, then load it into the new, empty database:
bash
gunzip wordpress_db.sql.gz
mysql -u wordpress_user -p wordpress_db < wordpress_db.sql
This runs on the destination server, using the database name and user created in Step 5. For a very large dump, this command can take a while — let it finish without interrupting it.
Step 7 — Update wp-config.php with the New Database Credentials
Open wp-config.php in the newly extracted site directory and update the four database constants to match what you created in Step 5:
DB_HOST is usually localhost when MySQL/MariaDB runs on the same server as PHP; change it only if the database is hosted elsewhere. While you're in this file, it's also good practice to regenerate the authentication unique keys and salts using WordPress's own secret-key generator, and paste the new block in over the old one — this invalidates any existing login cookies, which is expected after a server move.
“Do not skip this step — WordPress will show a "Error establishing a database connection" message if these values still point at the old server's database, even though the files and the imported database itself are otherwise correct.”
Step 8 — Update the Site URL with WP-CLI Search-Replace
If the domain or protocol is changing as part of this move (for example, adding HTTPS, or moving from a staging subdomain to the production domain), the old URL is hardcoded throughout the database — in wp_options, and often inside post content and serialized widget or plugin settings. A plain SQL UPDATE breaks serialized data because it changes string lengths without updating the serialized length prefixes; WP-CLI's search-replace command handles this correctly. Install WP-CLI on the destination server if it isn't already present:
--skip-columns=guid leaves the guid column untouched, which is the documented best practice — GUIDs are meant to be permanent identifiers, and RSS readers and some integrations rely on them not changing. If you'd rather do this by hand for just the two core URL options instead of a full search-replace, you can update them directly:
sql
UPDATE wp_options SET option_value = 'https://example.com' WHERE option_name = 'siteurl';
UPDATE wp_options SET option_value = 'https://example.com' WHERE option_name = 'home';
This manual approach only fixes the site's base URL, not any URLs embedded in post content, image src attributes, or serialized plugin settings — for anything beyond a bare protocol change, prefer wp search-replace.
Step 9 — Set File Permissions and Test Before Cutover
Set sane ownership and permissions on the extracted files so WordPress can write to uploads and manage updates, without making everything world-writable:
Before touching DNS, verify the site actually works on the new server. On your local machine, temporarily override DNS resolution for the domain by adding an entry to your hosts file (/etc/hosts on Linux/macOS, C:\Windows\System32\drivers\etc\hosts on Windows) pointing it at the new server's IP address:
bash
203.0.113.10 example.com www.example.com
With that entry in place, your browser resolves the domain straight to the new server while everyone else still hits the old one. Browse the site, log in to wp-admin, click through a few posts and pages, check that images load, and open the browser console to check for mixed-content warnings if you also changed the protocol to HTTPS. Remove the hosts file entry once you're done testing.
Step 10 — Point DNS at the New Server and Do a Final Verification
Once you've confirmed the site works correctly on the new server, and enough time has passed for the lowered TTL from Step 1 to be in effect everywhere, update the domain's A record (and AAAA record, if applicable) at your DNS provider to the new server's IP address. Propagation should now be fast given the shortened TTL, but confirm it from a machine that isn't using the hosts file override:
bash
dig +short example.com
Once the output consistently returns the new server's IP address, do a final pass through the live site: confirm forms submit correctly, check that cron-driven features (like scheduled posts) are firing, and if a caching plugin was part of the migrated wp-content, clear its cache so it isn't serving stale pages generated on the old server. If you added HTTPS as part of this move and haven't already, obtain a certificate for the domain — for example with Certbot — now that DNS resolves to the correct server.
“Keep the old server running and unchanged for a few days after cutover rather than decommissioning it immediately. If an issue surfaces post-migration, you can point DNS back at it while you investigate, and it also gives you an unmodified fallback copy of the pre-migration database and files.”
Once you're confident the new server is stable, restore the DNS TTL to its normal, longer value and decommission or repurpose the old server.
Conclusion
You exported the WordPress database with mysqldump, archived the site's files with tar, transferred both to a new server, recreated the database and imported the dump, pointed wp-config.php at the new database credentials, rewrote the site URL throughout the database with wp-cli search-replace where the domain or protocol changed, and verified the new server with a local hosts file override before finally cutting DNS over to it. The same sequence — export, archive, transfer, import, reconfigure, verify, cut over — applies whether you're moving to a larger server, a different provider, or simply consolidating multiple sites onto one host.