mysql容器重启丢数据90%是挂载失效:需优先验证/var/lib/mysql是否真实挂载到持久化存储,检查mounts中destination是否为该路径、source是否为命名卷或有效宿主机路径,并区分匿名卷(不可复用)与命名卷(推荐)。

MySQL容器重启后数据丢失,90%的情况不是MySQL问题,而是挂载没生效或挂载错了位置。 直接检查 /var/lib/mysql 在容器内是否真正指向持久化存储,比查MySQL日志更有效。
确认容器内 MySQL 数据目录是否被挂载
这是最优先验证的步骤。很多人以为加了 -v 就万事大吉,但实际挂载可能根本没落到 /var/lib/mysql 上。
- 进入容器执行:
docker exec -it some-mysql ls -ld /var/lib/mysql,看输出是否为drwxr-xr-x 1 root root(权限宽松)或drwx------ 1 mysql mysql(MySQL 自建目录)——前者大概率是空卷或宿主机目录未初始化,后者才是正常挂载后 MySQL 写入过的状态 - 再运行:
docker exec -it some-mysql find /var/lib/mysql -maxdepth 1 -type d | wc -l,如果只返回1(仅目录自身),说明里面是空的,挂载点存在但没数据,大概率是卷为空或挂载路径写错 - 用
docker inspect some-mysql查Mounts字段,确认Destination确实是/var/lib/mysql,且Source指向一个真实存在的命名卷(如/var/lib/docker/volumes/mysql-data/_data)或宿主机绝对路径
区分命名卷 vs 匿名卷:一眼识别是否“假持久化”
匿名卷(anonymous volume)是 Docker 在你写错 -v 参数时自动创建的“幽灵卷”,每次 docker run 都新建一个,数据永远不复用。
- 错误写法(危险!):
docker run -v /var/lib/mysql mysql:8.0→ 这会创建匿名卷,docker volume ls里看到的是随机哈希名,无法复用 - 正确写法(必须带名字):
docker run -v mysql-data:/var/lib/mysql mysql:8.0→mysql-data是你定义的卷名,docker volume ls中能稳定看到它 - 快速自查:
docker volume ls --filter dangling=true如果返回大量匿名卷,说明你长期在用错误挂载方式,历史数据早已散落在不同卷中
检查 MySQL 启动日志里有没有 “InnoDB: Database page corruption” 或 “Starting crash recovery”
如果挂载看似正常,但数据仍异常消失,可能是文件系统损坏,常见于强制 kill 容器、宿主机断电、或挂载了错误权限的宿主机目录。
- 执行:
docker logs some-mysql 2>&1 | grep -i -E "(corrupt|recovery|innodb.*error)" - 特别注意:
InnoDB: Unable to lock ./ibdata1表示多个容器同时挂载了同一个卷且没做并发控制,或上一次 MySQL 未正常关闭 - 若发现崩溃恢复失败,不要直接重启容器,先用
docker volume inspect mysql-data找到宿主机路径,手动备份_data目录,再尝试mysqld --innodb-force-recovery=1启动导出
真正容易被忽略的点是:MySQL 容器启动时,如果挂载的目标目录在宿主机上已存在且非空(比如之前用 bind mount 存过数据),但权限不是 mysql:mysql,MySQL 进程会静默失败并退出——此时容器可能因 restart policy 自动重启,形成“数据在、服务不在、你以为数据丢了”的假象。务必先看 docker ps -a 确认容器是否处于反复 restart 状态,再查日志。











