必须挂载/var/lib/mysql,否则容器删除后数据全丢;推荐用命名卷docker volume create mysql-data并-v mysql-data:/var/lib/mysql挂载,避免匿名卷导致重启丢数据。

MySQL在Docker容器里不配持久化,删容器就丢库——这不是bug,是设计使然。必须把/var/lib/mysql挂出去,否则谈不上备份。
为什么docker run -d mysql:8.0一删就丢数据?
默认启动的MySQL容器所有数据都写在容器可写层,属于临时文件系统。容器停止、删除、重建后,OverlayFS上层直接清空,ibdata1、mysql库全消失。
- 不是MySQL没保存,是它根本没机会写到宿主机
-
VOLUME /var/lib/mysql在官方镜像Dockerfile里声明了,但只是“声明”,不等于自动生效 - 没显式用
-v挂载,这个VOLUME就停留在镜像层,运行时无实际存储绑定
用docker volume挂/var/lib/mysql是最省心的方案
命名卷由Docker管理路径、权限和生命周期,不用操心UID、SELinux或macOS文件系统兼容性问题。
- 创建卷:
docker volume create mysql-data - 启动容器:
docker run -d --name mysql-prod -e MYSQL_ROOT_PASSWORD=123456 -v mysql-data:/var/lib/mysql -p 3306:3306 mysql:8.0 - 验证是否生效:停掉容器
docker stop mysql-prod && docker rm mysql-prod,再用同样命令重跑,连上去查SHOW DATABASES;,旧库还在就是挂对了 - 别手动进
/var/lib/docker/volumes/去碰文件——Docker不保证底层结构稳定,docker volume inspect mysql-data只用来定位,不用于操作
用宿主机目录挂载(bind mount)必须处理UID权限
MySQL容器内默认以用户mysql(UID 999)运行,宿主机目录若没对应权限,容器会卡在初始化阶段,日志里反复报mysqld: Can't create/write to file。
- 先建目录:
mkdir -p /mydata/mysql - 赋权(Linux):
chown -R 999:999 /mydata/mysql - macOS或Windows WSL要注意:NTFS/HFS+挂载可能触发权限降级或字符编码异常,首次启动失败时优先检查
docker logs mysql-local里有没有Permission denied或Operation not permitted - 不建议生产环境用bind mount——路径硬编码、迁移困难、宿主机磁盘故障直接影响数据库可用性
备份不能只靠挂载,得有可执行的导出流程
挂载解决的是“删容器不丢数据”,但防不了误删表、SQL注入破坏、磁盘静默损坏。必须定期mysqldump并存到独立位置。
- 别在MySQL容器里直接跑
mysqldump——会占用数据库连接和CPU,影响业务 - 推荐用专用备份容器:
docker run --rm -v mysql-data:/var/lib/mysql -v $(pwd)/backups:/backup mysql:8.0 bash -c 'mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" --all-databases > /backup/$(date +%Y%m%d_%H%M%S).sql' - 密码明文传参有风险?改用
--env-file或Docker secrets(Swarm模式下) - 备份文件别留在同一个卷里——万一卷损坏,备份和原数据一起完蛋;至少挂到另一个
backup-volume或同步到S3/MinIO
最常被跳过的其实是“首次初始化逻辑”:空目录挂载进去,MySQL会自动初始化;但已有数据的目录如果版本不兼容(比如用MySQL 5.7的ibdata1挂给8.0用),容器直接退出,docker logs里只显示Initialization of mysqld failed,没更多线索。这时候得看MySQL错误日志,而它默认写在/var/lib/mysql里——正好是你挂载的目录,得进去翻hostname.err。











