mysql_user仅在首次启动且/var/lib/mysql为空时创建用户并授权,不支持多库、细粒度权限或重启生效;生产环境必须通过/docker-entrypoint-initdb.d/脚本显式创建用户并指定认证插件。

MYSQL_USER环境变量只在空数据目录时生效
它不会自动创建用户、也不会自动授权,更不会在已有 volume 或重启后起作用。只要 /var/lib/mysql 目录非空(比如挂载了持久卷),整个初始化逻辑直接跳过,MYSQL_USER 和 MYSQL_PASSWORD 就完全失效。
常见错误是以为设了这两个变量,应用就能连上 app_user——结果发现连 root 都登不进去,或者新用户根本不存在。
-
MYSQL_USER只会在首次启动且数据目录为空时,创建一个用户名为该值、主机为'%'的用户 - 它只对
MYSQL_DATABASE对应的库授予ALL PRIVILEGES,不支持多库、角色、只读权限等任何细粒度控制 - 认证插件固定为
caching_sha2_password(MySQL 8.0+ 默认),老客户端可能直接报错Authentication plugin 'caching_sha2_password' cannot be loaded
必须用 /docker-entrypoint-initdb.d/ 下的 SQL 脚本显式建用户
这才是生产环境唯一可控的方式。脚本会在容器首次初始化时按字母序执行,且可重复运行(需保证幂等)。
关键点不是“能不能写”,而是“怎么写才不出错”:
- 用户创建必须显式指定认证插件:
CREATE USER 'app_ro'@'%' IDENTIFIED WITH mysql_native_password BY 'pass123';(如需兼容旧客户端) - 授权语句必须带主机名:
GRANT SELECT ON mydb.* TO 'app_ro'@'%';,不能写'localhost'—— 容器间通信走的是 bridge 网络,host 是服务名或 IP,不是 localhost - 不要写
FLUSH PRIVILEGES;:DCL 语句(CREATE USER、GRANT)本身就会刷新权限系统,手动刷反而可能干扰内部状态 - 角色需提前创建,并用
SET DEFAULT ROLE激活:CREATE ROLE 'reader'; GRANT SELECT ON *.* TO 'reader'; GRANT 'reader' TO 'app_ro'@'%'; SET DEFAULT ROLE 'reader' TO 'app_ro'@'%';
Docker Compose 中避免密码硬编码
把密码写死在 environment 块里等于把密钥明文塞进版本库。哪怕只是测试环境,也建议拆出来。
推荐做法是分层隔离:
- 用
env_file加载.env文件,其中定义MYSQL_ROOT_PASSWORD、APP_USER_PASS等变量 - SQL 初始化脚本里用占位符?不行——容器内不支持变量替换。正确做法是:脚本内容固定,密码由外部注入(如通过 CI/CD 替换模板),或直接依赖
env_file提供的值做预处理 - 生产环境必须用 Docker Secrets,
mysql:8.0镜像原生支持从/run/secrets/读取密码文件,例如:CREATE USER 'app'@'%' IDENTIFIED BY (SELECT LOAD_FILE('/run/secrets/app_password'));
挂载脚本后仍连不上?先查认证插件和连接地址
90% 的“用户创建了但连不上”问题,都卡在这两个地方:
- 检查用户实际使用的认证插件:
SELECT user, host, plugin FROM mysql.user WHERE user = 'app_user';。如果显示caching_sha2_password,而你的 Python/PHP 客户端没装对应插件,就必然失败 - 确认连接地址不是
localhost:Docker 内部网络中,应用容器访问 MySQL 容器要用服务名(如mysql),不是127.0.0.1;本地调试时也应连宿主机 IP 或host.docker.internal(macOS/Windows),而非localhost - 验证用户是否被正确授权:
SHOW GRANTS FOR 'app_user'@'%';,注意输出里是否有ON mydb.*,而不是ON *.*或空行
初始化脚本跑完不代表权限立刻可用——MySQL 8.0 的权限变更实时生效,但客户端缓存、DNS 解析、甚至 Docker 网络延迟都可能造成短暂不可见。别急着重跑容器,先 docker logs 看 initdb 日志有没有报错。











