Choosing between dump, volume copy, or replication
A server change, a hosting provider switch, or consolidating multiple Docker hosts eventually requires moving a running database container from one machine to another. Depending on data volume, downtime tolerance, and network connectivity between hosts, logical dumps, raw volume copies via rsync, or a replication cutover each suit different scenarios, with their own pitfalls around consistency and integrity.
Table of Contents
- 1. Why the migration method decides success or failure
- 2. Logical dump: mysqldump and pg_dump in detail
- 3. Raw volume copy with rsync and tar
- 4. Replication cutover for minimal downtime
- 5. Network between hosts: SSH tunnels and bandwidth
- 6. Version compatibility and storage engine differences
- 7. Planning and communicating the downtime window
- 8. Validating integrity after migration
- 9. Migration methods compared directly
- 10. Summary
- 11. FAQ
1. Why the migration method decides success or failure
Having to migrate a database container between hosts is one of those moments where the choice of the right method directly translates into downtime and data loss risk. Unlike stateless application containers that can simply be redeployed, a database container carries state that must remain consistent at every step of the migration. A wrong move, such as copying a volume while the database is still writing, can produce a corrupted copy that only shows up the next time it starts on the new host.
The choice of method depends largely on three factors: data volume, tolerable downtime, and network connectivity between source and target host. Anyone who needs to migrate a database container between hosts while moving only a few gigabytes often gets by with a simple dump. With several hundred gigabytes or a zero downtime requirement, the method becomes considerably more complex. The following sections compare the three common approaches and show when each is the right choice.
2. Logical dump: mysqldump and pg_dump in detail
The logical dump is the simplest and most portable method to migrate a database container between hosts. mysqldump produces an SQL file with all CREATE and INSERT statements, which is simply replayed on the target host. The critical parameter for InnoDB tables is --single-transaction, which runs the dump within a single transaction with a consistent snapshot, without locking tables for the duration of the export. Without this parameter, a dump can capture inconsistent intermediate states during concurrent writes.
The great advantage of a logical dump lies in its version and architecture independence: an SQL file can easily be replayed from an older MySQL version into a newer one, even across different CPU architectures such as from x86 to ARM. The downside is speed with large data volumes, since every row is executed individually as an INSERT. With several hundred gigabytes, a dump based migrate a database container between hosts process can take several hours, while a raw volume copy finishes in a fraction of that time.
#!/usr/bin/env bash
# migrate-via-dump.sh — consistent logical dump migration
set -euo pipefail
SOURCE_CONTAINER="mysql-prod"
TARGET_HOST="db2.internal.mironsoft.de"
DUMP_FILE="/tmp/migration-$(date +%Y%m%d).sql.gz"
# Consistent snapshot dump, no table locking for InnoDB
docker exec "$SOURCE_CONTAINER" \
mysqldump --single-transaction --routines --triggers \
-u root -p"${MYSQL_ROOT_PASSWORD}" --all-databases | gzip > "$DUMP_FILE"
echo "[INFO] Dump size: $(du -h "$DUMP_FILE" | cut -f1)"
# Transfer over SSH to target host
scp "$DUMP_FILE" "deploy@${TARGET_HOST}:/tmp/"
# Restore on target
ssh "deploy@${TARGET_HOST}" \
"gunzip -c /tmp/$(basename "$DUMP_FILE") | docker exec -i mysql-new mysql -u root -p\${MYSQL_ROOT_PASSWORD}"
echo "[OK] Dump-based migration complete"
3. Raw volume copy with rsync and tar
The second method to migrate a database container between hosts is directly copying the data directories via rsync. This method is significantly faster than a logical dump because raw bytes get transferred instead of parsing and replaying SQL. The prerequisite, however, is that source and target database use exactly the same major version and the same storage engine, since the binary data format is otherwise incompatible.
The critical step in a volume copy is stopping the database before copying so no open file handles or partially written pages get copied along. A second, optional rsync pass before the actual stop significantly reduces downtime, because the first pass already transfers the bulk of the data while the database is still running, and only the diff needs to be transferred after the stop. This two stage approach makes the migrate a database container between hosts process considerably more practical for large data volumes.
#!/usr/bin/env bash
# migrate-via-rsync.sh — two-pass rsync to minimize downtime
set -euo pipefail
TARGET_HOST="db2.internal.mironsoft.de"
VOLUME_PATH="/var/lib/docker/volumes/mysql-data/_data"
# Pass 1: sync while database is still running (bulk transfer)
echo "[INFO] First pass — database still running"
rsync -avz --delete "${VOLUME_PATH}/" "deploy@${TARGET_HOST}:${VOLUME_PATH}/"
# Pass 2: stop database, transfer remaining diff only
echo "[INFO] Stopping source database for final consistent sync"
docker stop mysql-prod
rsync -avz --delete "${VOLUME_PATH}/" "deploy@${TARGET_HOST}:${VOLUME_PATH}/"
# Start database on target host
ssh "deploy@${TARGET_HOST}" "docker start mysql-new"
echo "[OK] Volume copy migration complete, downtime limited to final diff sync"
4. Replication cutover for minimal downtime
Where downtime is practically not tolerated, a replication cutover is the right choice to migrate a database container between hosts. In this approach, the new host is first set up as a replica of the old host, using the native replication feature of MySQL or PostgreSQL. While the replica continuously picks up changes from the primary, the application keeps running unchanged against the old host until the replica is fully in sync.
The actual move then reduces to a brief cutover moment: stop the application, let the last changes replicate, promote the replica to the new primary, start the application with the new connection string. This cutover typically takes only a few seconds instead of hours, because the bulk of data transfer has already completed before the actual switch. The effort to set up replication is higher than for a dump or rsync, but it pays off when a migrate a database container between hosts process must happen during live business operation without noticeable interruption.
#!/usr/bin/env bash
# cutover.sh — final steps after replication has caught up
set -euo pipefail
# 1. Confirm replica lag is zero before cutover
docker exec mysql-replica mysql -u root -p"${MYSQL_ROOT_PASSWORD}" \
-e "SHOW REPLICA STATUS\G" | grep "Seconds_Behind_Source"
# 2. Stop application to prevent new writes on old primary
docker stop app-container
# 3. Wait for final events to replicate, then promote replica
docker exec mysql-replica mysql -u root -p"${MYSQL_ROOT_PASSWORD}" \
-e "STOP REPLICA; RESET REPLICA ALL;"
# 4. Point application at new primary and restart
sed -i 's/DB_HOST=db-old/DB_HOST=db-new/' .env
docker start app-container
echo "[OK] Cutover complete, application now writes to new host"
5. Network between hosts: SSH tunnels and bandwidth
Every method to migrate a database container between hosts depends on a reliable and secure network connection between the two machines. An SSH tunnel is the standard way to transfer data encrypted between hosts without exposing database ports directly to the open internet. For rsync and scp, this encryption happens automatically, while a direct replication connection should additionally have TLS configured between the database instances.
The available bandwidth between hosts largely determines which method is practical. Over a slow connection between two data centers, even a compressed dump can take several hours to transfer, while the same migration within the same data center or over a dedicated leased line finishes within minutes. Anyone planning to migrate a database container between hosts should estimate actual transfer time in advance with a test run of smaller data volumes, rather than relying on theoretical bandwidth figures.
6. Version compatibility and storage engine differences
A commonly underestimated aspect when trying to migrate a database container between hosts is version compatibility between source and target. With a raw volume copy, the target database must use exactly the same or a compatible major version, since the binary storage format of InnoDB can change between major releases. A volume copied from MySQL 8.0 and attached to MySQL 5.7 will, at best, simply not start, and at worst produce silent data corruption.
A logical dump avoids this problem entirely, since SQL statements get interpreted independent of version. So anyone planning a simultaneous host and version change, for example from MySQL 5.7 to MySQL 8.0, should prefer the dump approach over raw volume copy, even if the migration takes longer as a result. A migrate a database container between hosts undertaking with a simultaneous version jump but no dump is one of the most common patterns behind databases that no longer start after migration.
7. Planning and communicating the downtime window
Regardless of the chosen method, every attempt to migrate a database container between hosts needs a realistically planned downtime window. Planning should account not only for the pure transfer time, but also time for post migration validation, a possible rollback, and the DNS or load balancer switchover to the new host. A window planned too tightly often leads teams to skip validation steps under time pressure.
For business critical systems, a dry run of the entire migration on a copy of production data is recommended before the actual downtime window begins. This dry run surfaces surprises such as missing permissions, misconfigured network rules, or unexpectedly long runtimes before they cause nasty surprises during the real production window. A well prepared migrate a database container between hosts process differs from an improvised one mainly through this prior test run.
8. Validating integrity after migration
After every attempt to migrate a database container between hosts, data integrity on the new host must be verified before the old host is shut down. A simple first step is comparing row counts and table sizes between old and new host for all critical tables. Deviations in these numbers indicate an incomplete transfer or an error during the dump.
For a deeper check, a checksum comparison of individual tables is suitable, for example with pt-table-checksum from the Percona Toolkit, which reliably reveals content differences between two MySQL instances. Only after successful validation should the old host be taken out of production, ideally with a transition period during which it remains reachable as a fallback in case unexpected problems still surface after the migration.
9. Migration methods compared directly
The three approaches presented differ significantly in speed, downtime, and setup complexity. The following table summarizes when each method is the right choice to migrate a database container between hosts.
| Method | Downtime | Version change possible | Recommendation |
|---|---|---|---|
| Logical dump | High with large data volumes | Yes | Small to medium databases, version changes |
| Volume copy (rsync) | Low with two passes | No, same version required | Large data volumes, same DB version |
| Replication cutover | Minimal, seconds | Conditional, depends on replication logic | Zero downtime requirements, high effort |
For most small to medium production environments, a logical dump with --single-transaction is the most pragmatic way to migrate a database container between hosts, because it is straightforward, version independent, and easily testable. Only for very large data volumes or hard zero downtime requirements does the additional effort for volume copy or replication pay off.
Mironsoft
Docker infrastructure, database migrations, and zero downtime deployments
Moving database containers between hosts without headaches?
We plan and support your database migration, choose the right method for your data volume and downtime requirements, and validate data integrity after the move.
Migration Plan
Jointly defining method, downtime window, and rollback strategy
Dry Run
Full test run on a copy of production data before the real move
Integrity Check
Checksum comparison and validation before shutting down the old host
10. Summary
Anyone who needs to migrate a database container between hosts should choose the method based on data volume, downtime tolerance, and version compatibility. A logical dump with mysqldump --single-transaction is straightforward and version independent, but slower with large data volumes. A raw volume copy via rsync is fast but requires identical database versions. A replication cutover reduces downtime to seconds but demands more preparation effort.
Regardless of the chosen method, a realistically planned downtime window, a prior dry run, and a post migration integrity check belong on the mandatory checklist. A migrate a database container between hosts process without these safeguards is an unnecessarily high risk for production systems.
Migrating Database Containers Between Hosts — Key Takeaways at a Glance
Logical Dump
mysqldump --single-transaction is version independent but slower with large data volumes.
Volume Copy
Two pass rsync minimizes downtime but requires an identical database version.
Replication Cutover
Reduces downtime to seconds, but with a higher setup effort for replication.
Validation
Check row counts, checksums, and dry runs before shutting down the old host.