重启后数据丢失主因是/var/lib/mysql未真正持久化:90%系挂载失效或误用匿名卷;须进容器验证ls -ld权限、find查子目录数、inspect核对Mounts中Destination与Source,再区分命名卷与匿名卷并修正权限。

重启后数据丢失,不是MySQL坏了,而是/var/lib/mysql根本没落到持久化位置——90%的情况,挂载压根没生效,或挂到了匿名卷上。
确认/var/lib/mysql是否真实挂载
别信命令写了没,要进容器看实际路径状态:
- 执行
docker exec -it some-mysql ls -ld /var/lib/mysql,如果输出是drwxr-xr-x 1 root root,说明挂载点存在但没被MySQL写入(大概率是空卷或挂载失败);如果是drwx------ 1 mysql mysql,才表示MySQL已成功初始化并写入 - 再跑
docker exec -it some-mysql find /var/lib/mysql -maxdepth 1 -type d | wc -l,返回值大于1才有子目录(如ibdata1、数据库名),只返回1就等于空目录 - 用
docker inspect some-mysql查Mounts字段:确保Destination是/var/lib/mysql,且Source指向命名卷(如/var/lib/docker/volumes/mysql-data/_data)或宿主机绝对路径,而不是随机哈希名
区分命名卷 vs 匿名卷:一眼识别“假持久化”
匿名卷是Docker的自动兜底行为,每次docker run都新建一个,旧数据永远找不回来:
- 错误写法:
docker run -v /var/lib/mysql mysql:8.0→ 创建匿名卷,docker volume ls里看到的是5f8a2b1c...这类哈希名 - 正确写法:
docker run -v mysql-data:/var/lib/mysql mysql:8.0→mysql-data是显式定义的卷名,docker volume ls能稳定列出 - 快速扫雷:
docker volume ls --filter dangling=true,如果有大量返回,说明历史操作一直在制造“数据孤岛”
绑定挂载时权限不匹配,MySQL自动退到可写层
用-v /host/path:/var/lib/mysql这类宿主机路径挂载,最容易因UID/GID不一致导致写入失败:
- 先查容器内MySQL用户UID:
docker exec some-mysql id -u mysql(常见为999) - 再改宿主机目录权限:
sudo chown -R 999:999 /host/path,否则MySQL启动时发现无法写入/var/lib/mysql,就会静默退回到容器可写层,所有数据重启即丢 - 生产环境更建议直接用命名卷(
docker volume create mysql-data),Docker自动处理权限,省去手动干预和误判风险
验证持久化是否真正生效的闭环动作
挂载命令只是开始,必须走完三步验证才算落地:
- 启动容器后,手动建库插一条记录:
CREATE DATABASE test; INSERT INTO test.t VALUES (1); - 执行
docker stop && docker rm && docker run重建容器(注意:不删卷) - 进新容器检查:
ls /var/lib/mysql/test是否存在,或直接连MySQL查SELECT * FROM test.t;——只有这一步通过,才能确认数据真正在卷里,而不是在某个随时会消失的可写层上
最常被忽略的一点:很多人以为docker restart会触发数据丢失,其实它根本不会动挂载关系;真正危险的是docker rm后重新run,或者docker-compose down没配volumes保留策略。持久化的关键不在“重启”,而在“卷是否跨容器复用”。


















