MySQL 8.4 容器启动后客户端连不上:Plugin ‘mysql_native_password‘ is not loaded
·
一、问题现场
用下面这个脚本启动 MySQL 容器:
docker run -d \
--name mysql8 \
--restart always \
-p 3306:3306 \
-v /Users/anchao/develop/mysql8/data:/var/lib/mysql \
-v /Users/anchao/develop/mysql8/logs:/var/log/mysql \
-v /Users/anchao/develop/mysql8/conf.d:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=Root@123456 \
-e TZ=Asia/Shanghai \
mysql:8.4.11
挂载的 my.cnf 内容:
[mysqld]
port=3306
bind-address=0.0.0.0
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
max_connections=500
default-authentication-plugin=mysql_native_password
lower_case_table_names=1
容器起来了,但客户端(DataGrip / IDEA Database)连接直接报错:
DBMS: MySQL (版本 8.0.46)
驱动程序: MySQL Connector/J (版本 mysql-connector-j-9.7.0,JDBC4.2)
[HY000][1524] Plugin 'mysql_native_password' is not loaded.
二、根因分析
这个报错的核心是 MySQL 认证插件的版本演进:
| MySQL 版本 | mysql_native_password 状态 | default-authentication-plugin |
|---|---|---|
| 5.7 | 默认认证插件 | 支持 |
| 8.0 | 仍内置,但已标记 deprecated | 支持(默认 caching_sha2_password) |
| 8.4 | 不再内置,退化为需手动加载的动态插件,且默认 OFF | 参数已被移除,改用 authentication_policy |
| 9.x | 彻底删除 | 已移除 |
所以问题链条是:
- 镜像用的是
mysql:8.4.11,该版本mysql_native_password默认没有加载。 my.cnf里的default-authentication-plugin=mysql_native_password在 8.4 中已经是无效参数(严格模式下甚至会导致启动失败)。- 客户端握手阶段服务端尝试用 native 插件校验,插件不存在 → 抛
ERROR 1524 (HY000)。
顺带一提:报错信息里显示的是
MySQL 8.0.46,说明连接的可能是另一个残留容器或旧数据目录初始化出来的实例。但无论 8.0 还是 8.4,根因都指向 native 认证插件的兼容性问题,排查时值得先确认真实版本。
三、三种解法
方案一(推荐):改用 caching_sha2_password
mysql-connector-j 8.0.9+ 起就已经完整支持 caching_sha2_password,9.7.0 更是没有任何问题。所以最简单的做法就是删掉那行历史遗留配置:
[mysqld]
port=3306
bind-address=0.0.0.0
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
max_connections=500
lower_case_table_names=1
重建容器:
docker rm -f mysql8 && bash mysql8/mysql.sh
如果 root 账号已经被初始化成 native 认证,进容器改回来:
docker exec -it mysql8 mysql -uroot -pRoot@123456 \
-e "ALTER USER 'root'@'%' IDENTIFIED WITH caching_sha2_password BY 'Root@123456'; FLUSH PRIVILEGES;"
⚠️ 坑点提醒:
lower_case_table_names属于初始化时才能确定的参数。如果/var/lib/mysql数据目录已经存在,且当前配置值与初始化时不一致,MySQL 会直接拒绝启动。遇到这种情况需要清空数据目录重新初始化(记得先备份)。
方案二:在 8.4 上强行启用 native 插件
如果老系统确实依赖 mysql_native_password(比如某些老版本 ORM、连接池或运维工具),8.4 里插件本体还在包中,只是需要显式加载:
[mysqld]
port=3306
bind-address=0.0.0.0
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
max_connections=500
lower_case_table_names=1
mysql_native_password=ON
authentication_policy=mysql_native_password
注意两点:
- 8.4 中不能再用
default-authentication-plugin,必须换成authentication_policy。 - MySQL 9.x 已经彻底删除该插件,此方案是死路一条,只是给你争取迁移时间。
方案三:降级镜像到 8.0
对认证方式没得选、又不想动配置的场景,直接把镜像换成 8.0 系列,原 my.cnf 可以原样使用:
docker run -d \
--name mysql8 \
--restart always \
-p 3306:3306 \
-v /Users/anchao/develop/mysql8/data:/var/lib/mysql \
-v /Users/anchao/develop/mysql8/logs:/var/log/mysql \
-v /Users/anchao/develop/mysql8/conf.d:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=Root@123456 \
-e TZ=Asia/Shanghai \
mysql:8.0.42
四、排查命令清单
遇到类似问题,先用这几条命令把现场摸清楚:
# 1. 确认真实版本 + 各账号使用的认证插件 + 插件加载状态
docker exec -it mysql8 mysql -uroot -pRoot@123456 \
-e "SELECT VERSION(); SELECT user,host,plugin FROM mysql.user; SHOW PLUGINS;"
# 2. 看启动日志,确认配置是否被拒绝
docker logs mysql8 --tail 50
# 3. 确认没有多个容器抢占 3306
docker ps -a --filter "publish=3306"
# 4. 确认配置文件确实被加载
docker exec -it mysql8 cat /etc/mysql/conf.d/my.cnf
其中 SELECT user,host,plugin FROM mysql.user; 是最关键的一条 —— 它能直接告诉你哪个账号卡在了 native 插件上。
五、经验总结
- 别再抄 5.7 时代的配置模板了。
default-authentication-plugin=mysql_native_password这行配置在网上流传了近十年,但从 8.4 开始它已经是错误配置。 - 镜像 tag 一定要写死小版本。
mysql:8或mysql:latest会在某次docker pull后悄悄从 8.0 跳到 8.4,然后你的服务在半夜挂掉。 - 认证插件迁移宜早不宜迟。9.x 已经删掉 native 插件,现在花十分钟把账号改成
caching_sha2_password,比将来大版本升级时被迫加班要划算。 - 初始化型参数要提前定好:
lower_case_table_names、character-set-server(部分场景)这类参数写进数据目录,改了就得重建。
更多推荐
所有评论(0)