Most WordPress migration tutorials will tell you to install a migration plugin. Then the plugin packages your entire site into a ZIP, you upload it to the new host, and unzip. Sounds simple. But in practice, you'll hit file size limits, plugin conflicts, broken image links after migration, and incomplete domain replacements.
I've been through those pitfalls. Then I switched to the command line. 30 minutes to migrate a 50GB site, no plugins, no timeout, no data loss.
This article tells you exactly how.
When CLI Migration Beats Plugin Migration
Plugin migration has three common problems:
File size limits. All-in-One WP Migration free tier caps at 512MB. Duplicator free tier has package size restrictions. A 50GB site? Plugin won't even start.
Timeout and memory limits. On shared hosting or low-end VPS, PHP execution time and memory limits will kill the migration process. You raise the limits, the plugin runs, and the server might 503 directly.
Plugin introduces extra risk. Migration plugins write data to the target site. If wp-config.php configuration differs slightly, the import may fail at the migration stage itself. Some hosts even block migration plugins outright.
CLI migration advantages: not bound by PHP configuration limits, transfers raw files, speed limited only by network bandwidth, fully automatable, suitable for recurring migration scenarios.
Pre-Migration Checklist: Verify Both Servers
Source server (old host) needs:
- SSH access
- mysqldump installed (usually pre-installed)
- wp-cli installed (`wp --info` to verify)
Target server (new host) needs:
- SSH access
- MySQL/MariaDB installed and running
- Nginx/Apache configured
- PHP installed and matching source server version
- wp-cli installed
Verify wp-cli installation (run on both servers):
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar && chmod +x phar && mv phar /usr/local/bin/wp
wp --info
Output containingWP-CLI v2.x.x means success.
Step 1: Package and Download Source Files
Run on source server, do not download the entire wp-content via FTP as it loses file permissions.
# Run in source site wp directory
cd /var/www/your-site.com/public_html
tar -czvf ~/site-backup.tar.gz . --exclude='./wp-content/cache' --exclude='./wp-content/upgrade'
The --exclude flags skip cache and upgrade temp files, reducing the archive by 30%-50%.
Then download to local (or rsync directly to new server):
scp user@old-server:~/site-backup.tar.gz ./
Step 2: Export Database (The Most Critical Step)
# Check current database configuration
wp config get DB_NAME DB_USER DB_PASSWORD DB_HOST --path=/var/www/your-site.com/public_html
# Export database
mysqldump -u DB_USER -p DB_NAME | gzip > ~/database-backup.sql.gz
Verify export integrity:
zcat ~/database-backup.sql.gz | grep -c "CREATE TABLE"
# Returns table count, should be between 12-80 (depending on plugins)
# WordPress core has 12 tables, plugins create additional ones
If the returned number is very small or empty, the export failed. Do not proceed.
Step 3: Upload Files to New Server
If the two servers can communicate directly, use rsync to skip local transit, faster with resume support:
rsync -avz -e ssh --progress ~/site-backup.tar.gz user@new-server:~/
If going through local transit is needed, tar+scp is sufficient.
Step 4: Extract and Configure on New Server
# Extract to site directory
mkdir -p /var/www/your-site.com
tar -xzvf ~/site-backup.tar.gz -C /var/www/your-site.com/public_html --strip-components=1
chown -R www-data:www-data /var/www/your-site.com/public_html
Step 5: Update wp-config.php (or Use wp-cli)
Create database and grant privileges on new server:
mysql -u root -p
CREATE DATABASE new_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
GRANT ALL PRIVILEGES ON new_db.* TO 'new_db_user'@'localhost' IDENTIFIED BY 'strong_password';
FLUSH PRIVILEGES;
EXIT;
Then update database connection info in wp-config.php:
wp config set DB_NAME new_db
wp config set DB_USER new_db_user
wp config set DB_PASSWORD strong_password
wp config set DB_HOST localhost
Step 6: Replace Domain (If Domain Changed)
This is the most critical step. WordPress stores domain data in serialized data in the database. Direct SQL global replace will corrupt the serialization structure, causing plugin settings to be lost.
Must use wp-cli's search-replace:
# Preview before replacing (does not actually execute)
wp search-replace 'https://old-domain.com' 'https://new-domain.com' --dry-run
# Execute after confirming
wp search-replace 'https://old-domain.com' 'https://new-domain.com' --precise
The --precise flag tells wp-cli to use PHP's unserialize rather than regex matching, ensuring serialized data is not corrupted.
Common issue: If migrating to new host but keeping the same domain, this step can be skipped.
Step 7: Import Database
zcat ~/database-backup.sql.gz | mysql -u new_db_user -p new_db
Verify import success:
wp db query "SELECT COUNT(*) FROM wp_posts;" --path=/var/www/your-site.com/public_html
Step 8: Clear Cache and Verify
# Delete wp-content/cache directory
rm -rf /var/www/your-site.com/public_html/wp-content/cache/*
# Verify wp-cli can read database
wp --path=/var/www/your-site.com/public_html core verify-checksums
# Verify media file URLs
wp media regenerate --only_missing --path=/var/www/your-site.com/public_html
Comparison of Three Approaches
| Method | Best For | Pros | Cons |
|---|---|---|---|
| Plugin Migration | Small sites (<500MB), beginners | GUI, simple | File size limits, plugin conflict risk |
| CLI Migration | Medium-large sites, tech-savvy users | Fast, no size limit, no plugin dependency | Requires SSH and basic Linux knowledge |
| Host Migration | All sites | Free, professional team handles it | Requires host support, time not in your control |
My recommendation: Duplicator for sites under 500MB with no domain change; CLI for 500MB+ or domain changes; use host's free migration service if you don't want to do it yourself.
Troubleshooting Post-Migration Issues
Issue 1: White Screen or 500 Error
Check PHP version: php -v, ensure it matches source server. WordPress 6.x requires PHP 7.4+.
# Check WordPress core PHP version requirements
wp core verify-checksums --path=/var/www/your-site.com/public_html
Issue 2: Images Return 404
Media file URLs exist in wp_posts post_content. If you ran search-replace, this shouldn't happen. If it does, check wp_options upload_path:
wp option get upload_path --path=/var/www/your-site.com/public_html
wp option update upload_path '/wp-content/uploads'
Issue 3: Too Many Redirects
Usually caused by SITEURL and HOMEURL in wp-config.php not matching the actual domain. Fix immediately:
wp option update home 'https://new-domain.com'
wp option update siteurl 'https://new-domain.com'
Issue 4: Database Import Error
May be a character set issue. Retry with flags:
zcat ~/database-backup.sql.gz | mysql -u new_db_user -p new_db --default-character-set=utf8mb4
What Makes 30-Minute Migration Possible
The core of the entire process is not any single command—it's removing the plugin as an intermediary layer. What a plugin does is simply packaging tar, mysqldump, SCP, and search-replace into a graphical interface. Once you understand this, you know why CLI is faster, more reliable, and more controllable.
If you migrate WordPress between hosts frequently, I recommend writing the above steps into a shell script. Spend 10 minutes writing it once, and every future migration runs with a single script.
👉 Want an even simpler approach? The MiniMax API can help you automate content update workflows—after site migration, batch-replacing content URLs doesn't require manual editing line by line, and AI-driven workflows make the entire process more efficient.
👉 Join now: https://platform.minimaxi.com/subscribe/token-plan?code=E5yur9NOub&source=link
📚 Related Articles:
- WordPress Child Theme Creation Complete Guide — Mechanics, Steps, and Battle-Tested Tips
- The Complete WordPress Website Building Guide 2026 — From Zero to Professional Site
🔗 Related Tech Articles
Deep dive into related technical topics: