mysql 8.0 容器中环境变量仅在首次初始化(/var/lib/mysql为空)时生效;重复启动需依赖/docke-entrypoint-initdb.d/*.sql执行建库建用户等操作,并须配置认证插件与字符集以确保兼容性。

MySQL 8.0 容器启动时,MYSQL_DATABASE、MYSQL_USER 等环境变量仅在 /var/lib/mysql 目录为空时生效;一旦数据目录已有初始化过的文件,这些变量会被完全忽略。
MYSQL_DATABASE 和 MYSQL_USER 只在首次初始化时起作用
MySQL 官方镜像的初始化逻辑很明确:只有当 /var/lib/mysql 是空目录(或不存在),容器才会执行初始化流程,并读取 MYSQL_DATABASE、MYSQL_USER、MYSQL_PASSWORD 等环境变量来建库、建用户、赋权。
- 如果挂载了已有数据的宿主机目录(比如之前跑过一次 MySQL 8.0),容器直接启动 mysqld,跳过所有环境变量驱动的初始化
- 哪怕你改了
MYSQL_ROOT_PASSWORD,只要数据目录非空,root 密码还是旧的——它不更新,只读取 -
MYSQL_DATABASE不会自动CREATE DATABASE IF NOT EXISTS,它只在初始化阶段创建一次库,之后再启动无效
想每次启动都确保库和用户存在?用 init.sql + /docker-entrypoint-initdb.d/
这是唯一可靠、可重复的方式。把建库、建用户、授权语句写进 SQL 文件,放到容器能自动执行的位置。
- 文件必须放在宿主机路径下,然后通过
-v ./init.sql:/docker-entrypoint-initdb.d/init.sql挂载 - 文件名任意,但后缀得是
.sql(镜像只执行/docker-entrypoint-initdb.d/*.sql) - 内容里必须显式写
CREATE DATABASE IF NOT EXISTS和CREATE USER IF NOT EXISTS,否则重复启动会报错 - 注意权限:SQL 文件里不要用
'hive'@'localhost',而要用'hive'@'%',否则 Docker 内其他容器连不上
MYSQL_ROOT_PASSWORD 不等于 root 密码持久化
这个变量只影响初始化阶段的 root 密码设定。它不会写入数据库系统表,也不会在后续重启中生效——密码实际存于 mysql.user 表中,由数据目录持久化。
- 如果你删了容器又重跑,但挂载了旧数据目录,
MYSQL_ROOT_PASSWORD的值完全没用 - 要改 root 密码,必须进容器执行
ALTER USER 'root'@'%' IDENTIFIED BY 'newpass'; FLUSH PRIVILEGES; - 若想“一劳永逸”,把改密语句也写进
init.sql,并加IF NOT EXISTS或用SET PASSWORD避免报错
容易被忽略的字符集与认证插件兼容性
即使环境变量和 init.sql 都配对了,客户端连不上往往不是密码问题,而是默认认证插件不匹配。
- MySQL 8.0 默认用
caching_sha2_password,但老 JDBC 驱动、Navicat 12 以下、部分 Python mysqlclient 会失败 - 必须在配置文件里显式设
default_authentication_plugin=mysql_native_password,且该配置需位于[mysqld]段内 - 挂载配置文件时,路径必须是
/etc/mysql/conf.d/*.cnf或/etc/mysql/my.cnf,不能只挂到/etc/mysql/根目录下 -
character-set-server=utf8mb4和collation-server=utf8mb4_unicode_ci也要同步配,否则 init.sql 里的中文注释或数据可能乱码
真正稳定的初始化,靠的是 init.sql 文件 + 正确挂载的数据目录 + 显式声明的认证插件和字符集——环境变量只是“第一次”的快捷方式,别指望它兜底。











