How to Migrate a WordPress Site: A Practical Step-by-Step Guide
Move a WordPress site from one host to another without downtime or data loss. This guide covers the full process from planning to DNS cutover.
Before You Start: The Migration Checklist
WordPress migrations fail in predictable ways. This checklist prevents most of them:
- [ ] Current site backed up (files + database)
- [ ] New hosting account provisioned and tested
- [ ] WordPress version, PHP version, and required extensions noted
- [ ] Domain registrar access available for DNS changes
- [ ] Current DNS TTL checked (lower it 24 hours before migration)
- [ ] SSH/SFTP access confirmed on new host
- [ ] New host PHP version matches or exceeds old host
Choose Your Migration Method
There are three main approaches:
| Method | Best For | Risk Level | Downtime |
|---|
| Manual (SSH) | Experienced users, full control | Low | Minimal |
|---|---|---|---|
| Duplicator plugin | Non-technical users | Low | Minimal |
| All-in-One WP Migration | Quick moves, small-medium sites | Medium | Minimal |
| Managed migration | Complex sites, enterprise | Low | None |
This guide covers the manual SSH method (most reliable) and the Duplicator method (most accessible).
Method 1: Manual Migration (SSH)
This is the most reliable method. You control every step.
Step 1: Backup the Current Site
SSH into your current server:
# Create backup directory
mkdir -p ~/wordpress-backup# Export database (replace with your credentials)
mysqldump -u DB_USER -p DB_NAME > ~/wordpress-backup/database.sql
# Archive the WordPress files
tar -czvf ~/wordpress-backup/wordpress-files.tar.gz /path/to/wordpress/
Keep the database backup separate from the file archive.
Step 2: Upload to New Server
# On your local machine, download the backups
scp user@oldserver:~/wordpress-backup/database.sql .
scp user@oldserver:~/wordpress-backup/wordpress-files.tar.gz .# Upload to new server
scp database.sql user@newserver:~/wordpress-backup/
scp wordpress-files.tar.gz user@newserver:~/wordpress-backup/
Or use rsync for efficiency:
rsync -avz --progress ~/wordpress-backup/ user@newserver:~/wordpress-backup/
Step 3: Prepare the New Server
# SSH into new server
ssh user@newserver# Create the web directory (adjust for your host's structure)
mkdir -p /var/www/yoursite.com
cd /var/www/yoursite.com
# Extract WordPress files
tar -xzvf ~/wordpress-backup/wordpress-files.tar.gz
# Move contents up one level if they extracted into a subdirectory
mv wordpress/* .
# Set permissions
chown -R www-data:www-data /var/www/yoursite.com
find /var/www/yoursite.com -type d -exec chmod 755 {} \;
find /var/www/yoursite.com -type f -exec chmod 644 {} \;
Step 4: Create the Database
# Login to MySQL
mysql -u root -p# Create the database
CREATE DATABASE wp_yoursite CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# Create the user
CREATE USER 'yoursite_user'@'localhost' IDENTIFIED BY 'STRONG_PASSWORD_HERE';
# Grant permissions
GRANT ALL PRIVILEGES ON wp_yoursite.* TO 'yoursite_user'@'localhost';
# Apply and exit
FLUSH PRIVILEGES;
EXIT;
Step 5: Import the Database
mysql -u yoursite_user -p wp_yoursite < ~/wordpress-backup/database.sql
Step 6: Update WordPress Configuration
Edit wp-config.php:
// Database
define( 'DB_NAME', 'wp_yoursite' );
define( 'DB_USER', 'yoursite_user' );
define( 'DB_PASSWORD', 'STRONG_PASSWORD_HERE' );
define( 'DB_HOST', 'localhost' );// If moving to HTTPS (add these)
define( 'WP_HOME', 'https://yoursite.com' );
define( 'WP_SITEURL', 'https://yoursite.com' );
// Recommended additions for migrations
define( 'FS_METHOD', 'direct' );
Step 7: Update URLs in Database
The database contains hardcoded URLs that must be updated:
mysql -u yoursite_user -p wp_yoursiteUSE wp_yoursite;
# Update posts and pages (GUID field must NOT be changed for posts)
UPDATE wp_posts SET post_content = REPLACE(post_content, 'http://oldserver.com', 'https://yoursite.com');
# Update options
UPDATE wp_options SET option_value = REPLACE(option_value, 'http://oldserver.com', 'https://yoursite.com') WHERE option_name IN ('home', 'siteurl');
# Update post meta
UPDATE wp_postmeta SET meta_value = REPLACE(meta_value, 'http://oldserver.com', 'https://yoursite.com');
# Update comments
UPDATE wp_comments SET comment_content = REPLACE(comment_content, 'http://oldserver.com', 'https://yoursite.com');
EXIT;
Important: If you're using a plugin that stores full URLs in serialised data (some cache plugins, page builders), you'll need to use WP-CLI for proper serialisation-safe replacements:
# Install WP-CLI if not present
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp# Run search-replace with serialisation support
wp search-replace 'http://oldserver.com' 'https://yoursite.com' --allow-root
Step 8: Configure the Web Server
For nginx:
server {
listen 80;
server_name yoursite.com www.yoursite.com;
root /var/www/yoursite.com;
index index.php; access_log /var/log/nginx/yoursite-access.log;
error_log /var/log/nginx/yoursite-error.log;
client_max_body_size 100M;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
}
Step 9: Test Before DNS Cutover
Add a temporary entry to your local hosts file to test the new server:
# macOS/Linux
sudo nano /etc/hosts# Add this line (use new server's IP address)
123.45.67.89 yoursite.com www.yoursite.com
Visit yoursite.com in your browser — it will now load from the new server. Test thoroughly:
- All pages load correctly
- Images and media display
- Forms submit correctly
- Admin login works
- Permalinks work
Method 2: Duplicator Plugin
For non-technical users, the Duplicator plugin handles most of this automatically.
Step 1: Install Duplicator
On your current site: 1. Install Duplicator by Life Response from the WordPress plugin directory 2. Activate the plugin 3. Go to Duplicator > Packages > Create New
Step 2: Configure and Scan
1. Name your package
2. Click Scan to check for issues
3. If archive is too large, exclude wp-content/uploads/ or cache directories
4. Store the archive and installer.php somewhere safe
Step 3: Upload to New Server
1. Download the archive.zip and installer.php files
2. Upload both to the new server's web directory
3. Visit yoursite.com/installer.php in your browser
Step 4: Run the Duplicator Installer
1. Enter the new database credentials 2. Enter the new site URL 3. Run the installation 4. Duplicator handles the URL replacements automatically
DNS Cutover: The Final Step
Lower TTL in Advance
Do this 24-48 hours before the migration:
# Check current TTL
dig +nocmd +noall +answer yoursite.com# If TTL is high (e.g., 86400 = 24 hours), lower it
# Update your DNS record to TTL: 300 (5 minutes)
Most registrars have DNS settings in their control panel.
Update DNS
Change the A record for yoursite.com (and www) to point to your new server's IP address. Set TTL back to a reasonable value (3600-86400) after the migration is confirmed working.
Monitor After Cutover
- DNS propagation takes 15 minutes to 48 hours
- Check
whatsmydns.netto see propagation status - Monitor your new server's access logs for incoming traffic
- Keep the old server accessible for 48 hours as a fallback
Troubleshooting Common Problems
"Too Many Redirects" Error
This usually means WP_HOME and WP_SITEURL don't match what's in the database.
// In wp-config.php, force the correct URLs
define( 'WP_HOME', 'https://yoursite.com' );
define( 'WP_SITEURL', 'https://yoursite.com' );
Images Not Loading
URLs in the database weren't updated properly. Run the search-replace again:
wp search-replace 'http://yoursite.com' 'https://yoursite.com' --dry-run --allow-root
# Review the output, then remove --dry-run to execute
Database Connection Error
Wrong credentials in wp-config.php. Double-check:
- Database name
- Database username
- Database password
- Database host (usually
localhost, sometimes a remote hostname)
White Screen of Death
Usually a PHP error. Enable debugging:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
Check wp-content/debug.log for the actual error.
Post-Migration Checklist
- [ ] All pages load correctly
- [ ] Images and media display
- [ ] Internal links work (no mixed content warnings)
- [ ] Admin area accessible
- [ ] Forms functional
- [ ] SSL certificate working (green padlock)
- [ ] CDN cache purged (if using one)
- [ ] Old host account cancelled or retained for rollback
Bottom Line
The manual SSH method is more reliable than plugins because you control every step and there are no size limits. The investment in learning the process pays off — you'll be able to migrate in 30 minutes once you've done it once.
Start migrations on a Tuesday or Wednesday. DNS propagation is fastest during business hours, and if something goes wrong, you have Thursday/Friday to fix it rather than scrambling on a weekend.
Rather than DIY? Let OpsHelp handle everything.
Managed hosting with support, security, backups, and monitoring — from £50/mo.