必须挂载/var/lib/mysql到宿主机绝对路径,否则容器删除后数据全丢;挂载失败因权限不符(需chown -r 999:999)导致初始化卡在“initializing database”或反复重启,因mysql 8.0以uid 999运行且依赖该目录读写完成首次初始化。

/var/lib/mysql 必须挂载到宿主机绝对路径,否则容器一删数据全丢。这是唯一不可妥协的硬性要求,其他配置都建立在此基础之上。
为什么 /var/lib/mysql 挂载失败会导致容器反复重启或卡在 Initializing database?
MySQL 8.0 官方镜像启动时,会检查 /var/lib/mysql 目录是否为空:为空则执行初始化(建系统库、设 root 密码);非空则直接加载现有数据。如果宿主机目录权限不对(比如 root 创建但未改属主),mysqld 进程(UID 999)无法写入,就会卡住或崩溃。
- 宿主机目录必须提前创建:
sudo mkdir -p /data/mysql8 - 必须设对属主:
sudo chown -R 999:999 /data/mysql8(不是chmod 777) - 不能挂载到空父目录(如
/data),也不能复用已有非 MySQL 数据的目录(会干扰初始化) - 常见错误日志:
mysqld: Can't open the mysql.plugin table或反复打印Initializing database
-v 挂载时,配置文件放哪才生效?
MySQL 8.0 容器按固定顺序加载配置:/etc/mysql/my.cnf → /etc/mysql/conf.d/*.cnf → /etc/mysql/mysql.conf.d/*.cnf。只挂一个文件,最稳妥的方式是放在 /etc/mysql/conf.d/ 下,且后缀为 .cnf,内容必须以 [mysqld] 开头。
- 推荐做法:
-v /host/conf.d:/etc/mysql/conf.d,然后在宿主机放/host/conf.d/01-charset.cnf,内容仅含[mysqld]及几行关键参数 - 必须包含:
default_authentication_plugin=mysql_native_password(否则旧 JDBC 驱动或 Navicat 连不上) - 必须显式设置:
default-time_zone='+8:00'(避免容器内时间与宿主机不一致) - 避免把自定义
my.cnf直接挂到/etc/mysql/my.cnf—— 会覆盖整个默认配置,容易漏掉关键项
环境变量如 MYSQL_ROOT_PASSWORD 为什么有时不生效?
它只在首次初始化时起作用。如果 /data/mysql8 目录里已有旧数据(哪怕是上次中断留下的残留),MySQL 就跳过初始化流程,直接加载数据——此时所有 MYSQL_* 环境变量全部被忽略。
- 典型表现:连上去发现 root 密码还是旧的,或
MYSQL_DATABASE指定的库没自动创建 - 解决方法:确认目录为空,或彻底清理重来:
sudo rm -rf /data/mysql8 && sudo mkdir -p /data/mysql8 && sudo chown -R 999:999 /data/mysql8 - 注意:不同小版本间的数据目录不完全兼容(如 8.0.32 和 8.0.36),混用可能导致启动失败
用 named volume 还是 bind mount?
生产环境更推荐 bind mount(即 -v /host/path:/var/lib/mysql),而不是 -v mysql8-data:/var/lib/mysql 这种 named volume。
- bind mount 的好处:备份、排查、迁移都直观,路径可见可控;能直接用
rsync或tar备份 - named volume 虽然免权限管理,但调试困难(
docker volume inspect查路径麻烦),且备份需额外导出命令 - 如果坚持用 named volume,请确保用
docker volume create mysql8-data显式创建,并确认其后端存储路径可访问
/var/lib/mysql 后,你得同步处理好它的“邻居”——比如日志目录(/var/log/mysql)、socket 文件路径、以及 tmpdir 是否也落在挂载点内。这些细节不处理,高并发或大事务时可能突然报错。











