☰
MySQL 8.0报错mysql_native_password is not loaded:原因排查与三种修复方案
2026/10/20 6:05:45 网站建设 项目流程

遇到Plugin 'mysql_native_password' is not loaded这个报错,通常意味着你正在跟 MySQL 8.0 及以上版本较劲,而且多半是在做账号认证、数据迁移或者客户端连接的时候撞上的。这条报错不算冷门,但第一次碰到的人很容易蒙圈,因为错误消息本身只说“插件没加载”,却没告诉你为什么没加载、去哪里加载、怎么才能绕过它。

我用几种不同的环境实测过这个报错,包括全新安装的 MySQL、从 5.7 升级上来的实例、还有 Docker 容器里跑的数据库。这篇就把根因、排查思路、三种可落地的解决方案一次性梳理清楚,顺便把那些容易误入的坑也标出来。

1. 问题成因拆解:这个报错到底在说什么

1.1 mysql_native_password 的身份

要搞懂这条报错,先得明白mysql_native_password是什么角色。它是 MySQL 历史上默认使用的身份认证插件,从 MySQL 4.1 开始就被广泛应用,一直到 MySQL 5.7 都是默认认证方式。它的工作原理是对用户密码做两次 SHA-1 加盐哈希,然后在服务端验证哈希值,认证过程不需要在服务端保存明文密码,也不需要通过网络传输明文密码。

这个插件用了二十多年,兼容性极好,几乎市面上所有老版本的客户端、驱动、中间件都认识它。但问题恰恰出在这个“老”字上。

1.2 为什么 MySQL 8.0 默认不再加载它

MySQL 8.0 发布时,Oracle 把默认认证插件换成了caching_sha2_password,理由很明确:mysql_native_password的 SHA-1 哈希算法安全性已经跟不上时代,而且它不支持下 TLS 保护密码传输之外的更安全的公钥交换机制。caching_sha2_password在认证速度、密码存储安全性上都有明显提升,所以 MySQL 团队决定把它设为默认值。

但需要注意,MySQL 8.0 并不是把mysql_native_password直接从代码里删掉了。插件本身还在,只是默认不启用、默认不加载。这就像工具箱里有一把螺丝刀,但厂家默认没把它摆在桌面上,你需要自己去抽屉里翻出来用。

1.3 触发这个报错的典型场景

根据我实测的经历,下面这些场景最容易踩中:

  • 从 MySQL 5.7(或更老版本)迁移过来的账号。老实例里创建的账号,认证插件字段存的是mysql_native_password。当你用文件系统拷贝数据目录或者导入旧备份的方式迁移到 MySQL 8.0 时,8.0 实例在验证这些老账号时,发现自己的插件列表里没有mysql_native_password,于是直接抛错。

  • 手动创建用户时显式指定了插件,比如写了CREATE USER 'xxx'@'%' IDENTIFIED WITH mysql_native_password BY '123456',但如果当前实例根本没有加载这个插件,同样会报错。

  • 某些发行版或云厂商提供的 MySQL 8.0 版本,为了安全策略,干脆把mysql_native_password插件从plugin目录里移除了。我在某个精简版镜像里就遇到过,SHOW PLUGINS输出里根本看不到它,mysql.plugin表里也没有记录。这种情况光靠SET PASSWORD改账号是没用的,要么把插件文件放回去,要么彻底换认证方式。

  • PHP 老版本驱动、老代码连接数据库时报错。这类场景名义上是客户端报错,实际上服务端日志里也经常出现plugin is not loaded的记录。

把这些场景放在一起看,你会发现根因其实是同一个:服务端 MySQL 实例不认识mysql_native_password这个认证插件,所以在认证阶段直接拒绝。

2. 排查与预检:动手修改之前的必做步骤

2.1 确认 MySQL 版本与插件加载情况

无论你打算走哪条修复路线,第一步永远是确认当前实例的真实状态,不能靠猜。登录 MySQL 后执行:

SELECT VERSION();

得到类似8.0.x的版本号后,再看插件表:

SHOW PLUGINS;

重点关注输出里有没有mysql_native_password。如果看到这一行,说明插件在内存里是可用的;如果列表里没有,再看mysql.plugin表:

SELECT * FROM mysql.plugin WHERE PLUGIN_NAME = 'mysql_native_password';

如果表里也没有记录,那基本可以判断插件文件可能缺失,问题比想象中麻烦一点。

2.2 确认具体账号的认证插件状态

光知道全局情况还不够,你还要看看到底是哪个账号在报错。查询方式:

SELECT user, host, plugin FROM mysql.user;

正常情况下,MySQL 8.0 新建的账号plugin列应该是caching_sha2_password。如果发现某些账号的plugin列是mysql_native_password,这些就是潜在的报错源。

2.3 查看 MySQL 错误日志

在改任何配置之前,建议先翻一下错误日志,通常位于数据目录下的*.err文件,或者通过SHOW VARIABLES LIKE 'log_error';查到路径。我遇到过一种情况:表面上报错信息只出现在客户端,但日志里其实早就记录了类似[ERROR] [MY-010330] Plugin mysql_native_password reported: ''的提示,能帮你更快定位是插件加载失败还是账号引用问题。

如果你用的是 Docker 部署的 MySQL,日志看这里:

docker logs 容器名 --tail 100

2.4 备份与回滚预案

修改认证插件属于变更操作,原则上要留后路。最稳妥的做法是先把mysql.user表里受影响账号的元数据导出来:

mysqldump -u root -p --no-tablespaces --no-create-info --skip-triggers mysql user > user_backup.sql

这个备份文件很小,但在你操作失误时能帮你恢复原状。另外,任何涉及my.cnf的修改,都建议先复制一份原文件:

cp /etc/my.cnf /etc/my.cnf.bak.$(date +%Y%m%d)

3. 解决方案一:修改账号认证插件指向新默认插件

3.1 适用场景与核心思路

这个方案最适合的场景是:你的 MySQL 8.0 实例本身没有缺失插件文件,只是老账号仍然写着mysql_native_password,导致认证失败。核心思路很简单——把账号的认证插件改成caching_sha2_password,并重新设置密码。

之所以推荐优先做这个操作,是因为 MySQL 8.0 的caching_sha2_password才是官方主推的方向,长期维护、性能更好,跟未来版本兼容性也更强。

3.2 操作步骤

先用管理员账号登录 MySQL(通常是 root 或者其他有CREATE USER/ALTER USER权限的账号),执行:

ALTER USER '目标用户名'@'目标主机' IDENTIFIED WITH caching_sha2_password BY '新密码';

举个例子,假如报错账号是'appuser'@'%',你想把密码改成App@2024Pass,就执行:

ALTER USER 'appuser'@'%' IDENTIFIED WITH caching_sha2_password BY 'App@2024Pass';

如果不想改密码,只想换认证插件,可以用:

ALTER USER 'appuser'@'%' IDENTIFIED WITH caching_sha2_password;

但这招的前提是账号原本的密码哈希可以被重算出来——实际上 MySQL 在切换插件时会对已有密码进行转换,如果旧密码哈希算法不兼容,命令可能失败。这时候老老实实加上BY '新密码'最稳妥。

改完以后执行:

FLUSH PRIVILEGES;

3.3 批量修改的技巧

如果你要处理的账号不止一两个,手工敲ALTER USER太浪费时间。可以用动态 SQL 批量处理。先查出所有需要改的账号:

SELECT CONCAT('ALTER USER ''', user, '''@''', host, ''' IDENTIFIED WITH caching_sha2_password BY ''临时密码'';') FROM mysql.user WHERE plugin = 'mysql_native_password';

把输出的 SQL 语句复制出来执行即可。但要注意,这个办法会让所有被改账号统一使用同一个临时密码,改完以后必须让对应业务方或开发人员自己去改密码。

3.4 这个方案的副作用与避坑提醒

最直接的副作用是:所有使用老版本客户端的连接方可能连不上数据库。caching_sha2_password要求客户端驱动支持新的认证协议。JDBC 8.0.x 以上的驱动、Python 的mysql-connector-python8.0 版本、PHP 7.4 以上配合较新的 mysqli 扩展,这些才支持。如果你的应用还停留在非常老的版本,选这个方案要提前做驱动升级。

在我实测中,Java 应用最常见的问题是依赖了mysql-connector-java5.1.x 版本,连接新认证账号时直接抛Public Key Retrieval is not allowed。赶上这种情况,要么升级驱动,要么只能走后文提到的第二个方案。

4. 解决方案二:在 MySQL 8.0 中启用 mysql_native_password 插件

4.1 适用场景与核心思路

如果你的业务系统里有一堆老客户端短期内没法升级,甚至有些驱动已经停止维护,那么强制迁移到caching_sha2_password根本不可行。这时候就需要在 MySQL 8.0 中重新启用mysql_native_password插件。

MySQL 8.0.34 之前的版本,默认把mysql_native_password标记为 deprecated,但只要插件文件存在,你通过配置就能把它加载进来。核心思路是在my.cnf里显式声明要加载这个插件。

4.2 直接修改 my.cnf

打开 MySQL 配置文件,一般路径是/etc/my.cnf、/etc/mysql/my.cnf或者/etc/mysql/mysql.conf.d/mysqld.cnf,在[mysqld]段落里加一行:

[mysqld] mysql_native_password=ON

注意写法——不是plugin-load=mysql_native_password.so(虽然这样写理论上也能生效,但更推荐用mysql_native_password=ON这种开关式配置,语义更清晰,也更不容易被后续版本忽略)。

保存后重启 MySQL:

systemctl restart mysql

重启后验证:

SHOW PLUGINS;

输出里应该能看到mysql_native_password这一行,状态是ACTIVE。到这一步,实例已经重新认识这个老插件了,再连接老账号应该不会报Plugin is not loaded。

4.3 如果配置文件里加了还是不生效

这种情况我遇到过两次,原因各不相同。第一次是配置文件优先级问题:系统里存在多个配置文件,我改的那个根本不会被读取。排查方法是执行:

mysqld --verbose --help | grep -A 1 "Default options"

它会打印出按顺序读取的配置文件路径列表,你就能确认自己改对文件没有。

第二次是插件.so文件不存在。MySQL 8.0 的插件目录一般叫plugin_dir,执行:

SHOW VARIABLES LIKE 'plugin_dir';

然后在系统里看看这个目录下有没有mysql_native_password.so:

ls -la /usr/lib/mysql/plugin/ | grep mysql_native

如果文件不存在,说明你的发行版或镜像把插件裁剪掉了。解决方法是安装对应版本的mysql-community-server-compat或者从相同版本源码中提取插件文件,复制到插件目录后设置权限再重启。如果你用的是 Docker 镜像,更简单的办法是换一个更完整的镜像标签。

4.4 启用插件后的安全权衡

启用mysql_native_password相当于把旧的安全机制放回来了。它本身没有致命的已知漏洞,但如果你的数据库直接暴露在公网,使用旧插件的账号更容易被暴力破解或撞库攻击。我的建议是:

  • 只让确实无法升级的旧客户端使用mysql_native_password账号;
  • 新账号一律使用caching_sha2_password;
  • 设置数据库防火墙或安全组,限制旧客户端来源 IP;
  • 定期刷新账号密码,不要长期使用同一个静态密码。

5. 解决方案三:修改客户端连接参数,绕开插件缺失限制

5.1 适用场景

有些情况下,你既不想改服务端配置,也暂时不想动账号插件,只想让某个特定客户端尽快连上数据库跑起来。这时候可以考虑从客户端角度做调整。

这个方案只适用于客户端本身就支持caching_sha2_password的场景,只是默认配置里强制指定了mysql_native_password,或者驱动版本太老导致协商失败。

5.2 JDBC 连接串调整

Java 应用最常见的问题就是连接串里的authenticationPlugins或defaultAuthenticationPlugin被设置成了com.mysql.jdbc.authentication.MysqlNativePasswordPlugin。如果你用的是 MySQL Connector/J 8.0.x,去掉这个参数,让驱动自动和服务端协商即可。推荐的连接串:

jdbc:mysql://host:3306/dbname?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC

其中allowPublicKeyRetrieval=true很关键。caching_sha2_password在非 SSL 连接下,需要从服务器获取公钥做 RSA 加密传输密码,这个参数默认是关闭的,不开会报Public Key Retrieval is not allowed。

如果你的驱动版本较老,建议升级到mysql-connector-java8.0.30 以上,这个版本对caching_sha2_password支持已经很成熟。

5.3 Python 连接适配

PyMySQL从 1.0.0 版本开始完全支持caching_sha2_password,但有一个前提,需要在连接时加入:

import pymysql conn = pymysql.connect( host='127.0.0.1', user='appuser', password='App@2024Pass', database='appdb', charset='utf8mb4', # 关键参数:允许从服务器获取公钥,用于 RSA 密码加密传输 program_name='MyApp' )

实际上PyMySQL里没有直接的allowPublicKeyRetrieval参数命名,它默认就能处理公钥获取。如果你现在用的还是MySQLdb(mysqlclient),需要确认版本支持情况,老版本在连接新认证账号时会直接卡住。

5.4 PHP 与其它语言

PHP 的mysqli扩展在 PHP 7.4 之后基本兼容新认证插件,但如果你用的是mysql扩展(PHP 5.x 时代产物),那对不起,这个方案救不了你。PHP 5.6 及以下连接 MySQL 8.0 的新认证账号几乎必失败,唯一的出路就是升级运行时环境或走服务端插件方案。

5.5 客户端方案的局限

需要明确一点,客户端方案解决的是单一连接方的问题。如果报错的服务端本身因为插件缺失导致ALTER USER都无法执行,那客户端方案根本无从谈起。所以这个方案更适合作为服务端修复完成后的配套工作,而不是独立的主方案。

6. 实战排错记录:我踩过的坑与最终处理过程

6.1 案例背景

某模拟项目 X 的测试环境,原先跑在 MySQL 5.7 上,因为磁盘迁移误操作,数据目录被直接拷贝到一台新装的 MySQL 8.0 实例上。启动正常,但所有业务账号连接全部报Plugin 'mysql_native_password' is not loaded。

这台 MySQL 是用某 Linux 发行版自带包管理工具安装的极简版,插件目录里果然没有mysql_native_password.so。

6.2 排查步骤拆解

第一步,确认实例版本:

SELECT VERSION(); -- 8.0.32

第二步,查用户表:

SELECT user, host, plugin FROM mysql.user;

输出结果里几乎所有应用账号的plugin都是mysql_native_password,只有 root 是auth_socket和caching_sha2_password。

第三步,查插件表:

SHOW PLUGINS;

确实没有mysql_native_password的行。

第四步,查插件目录:

SHOW VARIABLES LIKE 'plugin_dir';

目录下文件列表里找不到mysql_native_password.so。

6.3 处理过程与选择逻辑

一开始我按直觉直接改了my.cnf加mysql_native_password=ON,重启后SHOW PLUGINS还是没有。后来确认是插件文件缺失,于是从一个相同大版本(8.0.32)的完整安装包里提取了mysql_native_password.so,复制进插件目录,设置root:root和755权限,再改配置重启,插件状态变为ACTIVE。

到这一步,老账号能正常连接了。但事情没完——我顺带用第二个方案把所有应用账号批量迁移到了caching_sha2_password,因为测试环境的客户端都能升级,没必要一直背着老插件带来的安全包袱。

6.4 这次排错沉淀的经验

  • 版本号要精确匹配:插件.so文件的 ABI 兼容性在大版本内部通常没问题,但如果你用 8.0.33 的文件放在 8.0.21 的实例里,轻则加载失败,重则导致 mysqld 启动异常,所以复制插件文件时一定看准版本。
  • 改配置别忘验证生效:my.cnf加参数后不是百分百生效,特别是存在多个配置文件或者使用include机制时,参数可能被覆盖。每次改完配置,至少执行一次SHOW PLUGINS或SHOW VARIABLES验证。
  • 密码和插件同时改,避免二次故障:如果你打算走caching_sha2_password,最好在业务低峰期操作,因为切换瞬间旧连接全部失效,应用侧需要重连。

7. 快速排查表:一条命令判断该走哪条路

检查项目命令/操作结果判断
当前版本SELECT VERSION();8.0+ 才需要考虑此问题
插件是否已加载SHOW PLUGINS;无记录说明未加载
插件是否注册SELECT * FROM mysql.plugin WHERE PLUGIN_NAME='mysql_native_password';无记录说明未注册
插件文件是否存在ls plugin_dir无.so文件说明被裁剪
哪些账号依赖旧插件SELECT user, host, plugin FROM mysql.user;关注plugin='mysql_native_password'的行
错误日志log_error变量指向的文件看有无插件加载失败记录

判断逻辑很简单:

  • 插件文件存在,且已注册→ 直接走方案一,把账号改到caching_sha2_password即可,不需要动服务端配置。
  • 插件文件存在,未注册→ 走方案二,在my.cnf加参数并重启。
  • 插件文件不存在→ 要么补文件(方案二变体),要么所有客户端升级后走方案一。
  • 客户端无法升级→ 只能走方案二,把老插件加载回来。

8. 最后想说的几点实操心得

处理这个报错,最关键的是先分清楚是账号的问题还是插件本身的问题。很多人一看到Plugin is not loaded就急着去改账号,结果插件文件根本不存在,改来改去还是报错。反过来,也有人先花半天时间找插件文件,却不知道其实只要把账号换到新插件,问题当场就解决了。

如果你想避免以后再被这个问题困扰,我建议在初始化 MySQL 8.0 实例时,就统一规划认证插件策略:

  • 新部署的实例,一律使用caching_sha2_password,不要为了省事给所有账号都指定mysql_native_password;
  • 如果业务线里有无法升级的老客户端,单独建一个库、单独分配账号,只给这些账号指定旧插件,减小影响面;
  • 做好监控,对使用mysql_native_password的账号做定期审计,一旦客户端完成升级,就立刻把账号迁回新插件。

迁移数据目录这种事,能不用文件拷贝就别用文件拷贝,优先走逻辑备份(mysqldump或mydumper),能少踩一大堆兼容性坑。这次如果你也碰到了类似的插件报错,对照上面几个方案按顺序排查,基本都能把问题收拾干净。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询