DATABASES
July 1, 2026

How to Migrate a Large WordPress Database Safely

9 min read
Author
CloudStick Team
WordPress Engineer
Share this article
How to Migrate a Large WordPress Database Safely
CloudStick
Database Guide

Why Large Databases Fail to Migrate

A 500 MB+ WordPress database migration fails for three predictable reasons: the dump gets interrupted by an SSH timeout on a slow connection, the import runs out of memory on tables with huge single rows (serialized option blobs), or a naive dump-and-import approach locks tables long enough to cause visible downtime on a site that's still live during the transfer.

Each of these has a specific, well-known fix — none of them require special tools beyond what MySQL/MariaDB already ships with.

Dump with Compression and Locking Control

# Compress on the fly to cut transfer size and time significantly
mysqldump --single-transaction --quick -u dbuser -p wp_example | gzip > wp_example.sql.gz
# --single-transaction avoids locking InnoDB tables during the dump
# --quick streams rows instead of buffering the whole table in memory

A 2 GB uncompressed dump typically compresses to 300–500 MB, which meaningfully shortens transfer time over SSH — always compress before transferring across servers, never after.

Transfer and Import in the Background

Run both the transfer and the import inside screen or tmux so an SSH disconnect doesn't kill a multi-hour import:

# Start a detachable session
screen -S db-migration
# Transfer, then import — safe to detach (Ctrl+A, D) and reattach later
scp wp_example.sql.gz newuser@203.0.113.10:/home/new/
gunzip -c /home/new/wp_example.sql.gz | mysql -u dbuser -p wp_example

Handle Tables Too Large for a Single Dump

If wp_postmeta or wp_options alone is multiple gigabytes — common on sites with years of accumulated transient rows or a bloated autoloaded options set — dump that table separately with a smaller batch size to avoid memory spikes, and clean up expired transients before migrating rather than after:

# Clean expired transients before dumping — often removes 30-60% of postmeta bloat
wp transient delete --expired
# Dump a single oversized table with a smaller net buffer
mysqldump --single-transaction --quick --net_buffer_length=16384 \
-u dbuser -p wp_example wp_postmeta | gzip > wp_postmeta.sql.gz

Verify Row Counts After Import

Compare row counts per table between source and destination before declaring the migration done — a truncated import from a timeout or disk-full error can succeed without an obvious error message, leaving a table silently short a few thousand rows:

mysql -u dbuser -p -e "SELECT table_name, table_rows FROM information_schema.tables WHERE table_schema='wp_example';"
Leave a comment
Full Name
Email Address
Message
Contents