Docker + MySQL: Why They Clash and How to Avoid Hair‑Pulling Pitfalls
This article analyzes common pitfalls when running MySQL inside Docker containers—such as data loss, resource exhaustion, insecure defaults, networking mishaps, and missing backups—and provides concrete, step‑by‑step remedies including volume persistence, resource limits, custom configs, security hardening, and automated backup strategies.
Why Docker + MySQL can be problematic
Docker provides isolation, portability and reproducible environments for MySQL, but misconfiguration can cause data loss, resource exhaustion, security exposure, network failures and backup gaps.
Five fatal pitfalls
❌ Pitfall 1: Data "Schrödinger" persistence
Scenario: After inserting test data, the container is restarted and the data disappears. Root cause: Docker containers are ephemeral; removing a container also deletes its filesystem, including /var/lib/mysql .
📦 Container lifecycle
┌─────────────────┐
│ Start → Run → Remove │
│ │
│ 💾 Data lives in /var/lib/mysql │
│ 🗑️ Container removal → Data loss │
└─────────────────┘❌ Pitfall 2: Resource allocation "guesswork"
Scenario: A test container runs fine, but in production MySQL consumes all memory and CPU, triggering the host OOM killer. Root cause: No resource limits were set, so MySQL monopolizes host resources.
# No limits – dangerous
docker run mysql:8.0
# With limits – safe
docker run --memory="1g" --cpus="2" mysql:8.0❌ Pitfall 3: Insecure default configuration
Scenario: The container uses the default root/root password and exposes port 3306 to the public internet. Root cause: Weak credentials and open ports make the database an easy target.
# Dangerous: expose to world
-p 3306:3306
# Safer: bind to localhost only
-p 127.0.0.1:3306:3306❌ Pitfall 4: Network misconfiguration "maze mode"
Scenario: Application containers cannot connect to the MySQL container, reporting Can't connect to MySQL server . Root cause: Incorrect Docker network mode or hard‑coded IPs instead of container names.
# Wrong: use IP
-h 172.18.0.3
# Correct: use container name (Docker DNS resolves it)
-h mysql_prod❌ Pitfall 5: Backup "non‑existent"
Scenario: After accidentally deleting a database, there is no backup to restore. Root cause: Assuming a Docker volume is a backup; however, docker volume rm can delete the data instantly.
Five rescue tips
✅ Tip 1: Persist data with volumes
Mnemonic: "Data must persist, Volume cannot be omitted!"
docker run --name mysql_prod \
-e MYSQL_ROOT_PASSWORD=StrongP@ssw0rd \
-v mysql_data:/var/lib/mysql \
-d mysql:8.0
# Verify volume
docker volume ls # shows mysql_data✅ Tip 2: Limit resources to keep the host stable
Mnemonic: "Limit resources, system stays alive!"
docker run --name mysql_prod \
--memory="2g" \
--memory-swap="2g" \
--cpus="2" \
--oom-kill-disable \
-d mysql:8.0Typical resource recommendations (adjust to workload):
Development / test: 512 MB‑1 GB memory, 0.5‑1 CPU core
Small production: 2‑4 GB memory, 2‑4 CPU cores
Medium production: 8‑16 GB memory, 4‑8 CPU cores
Large production: use a cluster, scale horizontally
✅ Tip 3: Custom MySQL configuration
Mnemonic: "Default config not enough, my.cnf to the rescue!"
# my-custom.cnf
[mysqld]
max_connections=500
innodb_buffer_pool_size=1G
slow_query_log=1
# Mount the config
docker run --name mysql_prod \
-v $(pwd)/my-custom.cnf:/etc/mysql/conf.d/custom.cnf \
-d mysql:8.0Common tuning parameters:
max_connections ≈ 200‑500 (avoid excessive connections)
innodb_buffer_pool_size ≈ 70 % of physical memory
slow_query_log = 1, long_query_time = 2 seconds
✅ Tip 4: Security hardening
Mnemonic: "Strong password, hidden port!"
docker run --name mysql_prod \
-e MYSQL_ROOT_PASSWORD=$(openssl rand -base64 32) \
-p 127.0.0.1:3306:3306 \
--network my_private_net \
-d mysql:8.0Password length > 16 characters, mixed case, numbers, symbols
Disable remote root login; create limited‑privilege accounts
Enable SSL for production connections
Rotate passwords regularly
✅ Tip 5: Automated backups
Mnemonic: "No backup, you’ll cry!"
# backup.sh
#!/bin/bash
CONTAINER="mysql_prod"
BACKUP_DIR="/backup/mysql"
DATE=$(date +%Y%m%d_%H%M%S)
docker exec $CONTAINER \
/usr/bin/mysqldump -u root -p$MYSQL_ROOT_PASSWORD \
--all-databases | gzip > $BACKUP_DIR/backup_$DATE.sql.gz
# Keep last 7 days
find $BACKUP_DIR -name "backup_*.sql.gz" -mtime +7 -deleteBackup strategy (example):
Full backup: once daily during low‑traffic window
Incremental: hourly using binary logs
Off‑site: weekly sync to object storage (OSS/S3) for disaster recovery
Troubleshooting mini‑play
🎭 Scenario 1: Container fails to start
# Check logs first (covers most issues)
docker logs mysql_prod --tail 50
# Common errors & fixes
❌ "Access denied for user 'root'@'localhost'"
✅ Verify MYSQL_ROOT_PASSWORD env var
❌ "Can't create directory '/var/lib/mysql'"
✅ Ensure volume mount permissions (chown -R 999:999 /host/mysql_data)🎭 Scenario 2: Connection timeout
# Diagnose network
docker network ls
docker inspect mysql_prod | grep Networks
docker exec mysql_prod ping app_container
# Quick fix: use container name instead of IP
# ❌ -h 172.18.0.3
# ✅ -h mysql_prod🎭 Scenario 3: Performance degradation
# Monitor resources
docker stats mysql_prod
# Inspect MySQL internals
docker exec -it mysql_prod mysql -uroot -p
> SHOW PROCESSLIST;
> SHOW ENGINE INNODB STATUS;Conclusion
Key practices for a stable Docker + MySQL deployment:
1️⃣ Persist data – use Docker volumes
2️⃣ Limit resources – prevent host OOM
3️⃣ Tune configuration – improve performance
4️⃣ Harden security – block unauthorized access
5️⃣ Automate backups – avoid data lossSigned-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Golang Shines
We share daily the latest Golang technical articles, practical resources, language news, tutorials, and real-world projects to help everyone learn and improve.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
