MySQL 改了容器密码仍 Access denied:先看已有数据卷
容器环境变量变化不等于已有数据库账号密码变化。先确认数据目录和账号匹配,再选择受控改密,保留数据与恢复路径。
修改 MYSQL_ROOT_PASSWORD 或 MYSQL_PASSWORD,重建 MySQL 容器后仍出现 ERROR 1045 (28000): Access denied。如果数据目录已经初始化,先别继续改环境变量:官方镜像的初始化变量不是每次启动都执行的账号修改命令,数据库里的旧账号密码可能仍在生效。
按已有数据目录、真实连接目标和账号匹配分别判断。已有数据需要保留时,删除卷再初始化不能作为改密步骤。
环境变量什么时候才会设置账号
官方镜像在数据目录为空时执行初始化,创建账号和数据库。若目录已有数据库,通常会保留现状,初始化变量不会替你重新设置已有账号。
先查看挂载来源和启动日志:
# 假设 Compose 服务名为 db
docker compose ps
docker compose logs --tail=100 db
docker inspect --format '{{json .Mounts}}' \
"$(docker compose ps -q db)"
.Mounts 可以帮助区分命名卷、匿名卷和宿主机绑定目录。重建容器并不等于清空这些目录。日志则用来判断这是首次初始化还是已有数据库启动,不要只看容器环境中的变量是否已经变成新值。
不要把 docker compose down -v、docker volume prune 或删除挂载目录放到生产排查的第一步。它们可能移除保存数据的卷或目录;丢弃原数据库再初始化会造成数据丢失,不能当作无损恢复。
确认客户端连到的是哪套 MySQL
宿主机同时装有 MySQL 时,客户端使用 localhost 可能通过本地 socket 连接宿主机实例,并非你以为的容器端口。需要测试一个发布到本机的 TCP 端口时,明确指定 TCP:
# 仅当数据库已发布到宿主机 127.0.0.1:3307
mysql --protocol=TCP -h 127.0.0.1 -P 3307 -u app -p
-p 不跟密码,让客户端交互提示输入,避免把密码写入命令历史。3307 是示例,必须对应实际端口映射。另一个容器通过同网络访问数据库时,通常使用 db:3306;应用容器中的 127.0.0.1 不指数据库容器。
错误中的 'app'@'某个地址' 是重要线索。MySQL 账号由用户名与来源主机共同匹配,app@localhost 和允许容器网段连接的账号不一定是同一个账号。密码正确也不保证来源主机匹配;还需检查账号锁定及认证方式。
有管理员访问时,修改已存在的账号
先用仍然有效的管理员账号连接,再查询实际账号条目。下面 SQL 面向 MySQL 8.0/8.4,不适用于把其他数据库产品当作完全等价替代:
SELECT User, Host, plugin, account_locked
FROM mysql.user
WHERE User IN ('root', 'app');
SELECT USER(), CURRENT_USER();
USER() 反映连接身份,CURRENT_USER() 反映实际匹配的认证账号。没有系统表权限时应请管理员处理,不要给普通应用授予读取整个系统账号表的权限。
确认匹配条目后,针对那个账号执行受控修改,例如:
-- 仅当已有账号确实为 'app'@'localhost',且插件为 caching_sha2_password
ALTER USER 'app'@'localhost'
IDENTIFIED WITH caching_sha2_password BY '替换为新的长随机密码';
这是改密语法示例,不能直接用于解决远程容器来源的账号匹配问题。远程账号应使用已确认的来源范围与权限,而不是为了让错误消失就把 root 开放给所有来源。改密会使新连接需要新凭据,应用连接池、后台任务和管理工具要按安排同步更新。SQL 或管理工具也可能记录输入,使用你已有的凭据管理与审计方式处理真实密码。
修改前保留有效备份,明确当前可用凭据及恢复步骤;若需要回退,在管理通道可用时恢复账号凭据和应用配置。示例明确保留已确认的 caching_sha2_password 插件;只写 IDENTIFIED BY 在 MySQL 8.4 中会使用默认插件,不能假定它一定保留原来的认证方式。插件不符时先查对应版本的账号管理文档,不能随意切换认证插件或重装数据库。
变量值也可能与你写下的不一样
Compose 会展开配置中的美元符号。直接写在 YAML 中的密码、列表形式中带额外引号的值,以及不同配置文件的合并,都可能让真实值偏离预期。这是配置解析问题,不能简化成“某些字符不能作为 MySQL 密码”。
检查环境变量展开和秘密文件的来源,但不要把完整密码、authentication_string 或带凭据的 docker compose config 输出公开。修改已有容器变量仍不会自动修改已有数据库账号,因此要同时核对服务端账号和应用端凭据,不能只改一边。
如果管理员也无法登录,需要按对应版本的正式密码恢复流程维护数据库,安排停机、访问隔离和恢复;不能靠删除业务目录来恢复访问。只有确定数据可丢弃的临时开发环境,才考虑重新初始化,而且先明确要移除的是哪一个目录或卷。
修复后用应用的真实账号验收
从应用所在网络,用它自己的账号和连接目标建立新连接,读取必要的业务数据,确认账号匹配和权限符合预期。管理员能登录并不能替应用完成验收。再检查后台任务和新建连接不再报 1045,同时确认旧数据仍在。


