
看到ERROR 1524 (HY000) Plugin mysql_native_password is not loaded这个报错的时候很多人的第一反应是“我密码输错了”于是反复重试、重置密码折腾半天才发现根本不是密码的问题。这个错误我这两年处理过不少次基本都出现在 MySQL 升级、迁库、换容器镜像之后。它表面上是一个登录失败本质上却是数据库内部的认证插件“缺位”了。这篇文章就把这个报错从现象到根因、从救急到彻底解决讲透适合正在排查 MySQL 连接故障的人也适合准备做 MySQL 大版本升级、想提前避坑的人。1. 报错现场拆解为什么密码输对了仍然进不去1.1 报错的直接表现和容易被带偏的方向这个报错的典型现场是执行mysql -u root -p输入密码后终端直接抛来一行ERROR 1524 (HY000): Plugin mysql_native_password is not loaded。有些场景下是应用程序连接池报错后端日志里出现同样的 1524 代码业务方以为密码被盗用了急急忙忙去改密码结果越改越乱。要理解这个报错先要明确一件事MySQL 的登录校验并不只是“对一对密码字符串”它有一个完整的认证流程。服务端拿到客户端的连接请求后会先去mysql.user表里找到对应的用户名和来源主机然后读取这个账号记录里的plugin字段再根据这个字段去加载对应的认证插件。账号的密码校验完全交给这个插件去做插件返回成功这次握手才算通过。如果服务端在插件注册表里找不到mysql_native_password这个插件那么就算你把密码输入一万次服务端也无法完成校验只能返回 1524。所以这个错误跟密码正确与否没有任何关系问题出在上游——认证插件的加载环节。1.2 错误家族里的姊妹问题别把 1524 和 1045、2002 混为一谈排查这类问题最怕先入为主。我见过不少同事把 1524 当成 1045访问被拒绝来处理浪费时间。这三个报错在登录环节里分别指向不同的故障点报错代码含义故障点2002 (HY000)通过 socket 无法连接本地 MySQL网络、socket 文件路径、服务没有启动1045 (28000)Access denied for user账号密码校验失败、账号不存在、主机限制1524 (HY000)Plugin xxx is not loaded认证插件没有加载无法执行校验如果 MySQL 服务本身是好的报错却是 1524基本可以跳过网络排查直接去看服务端的插件体系。如果错误日志里同时出现 “Authentication plugin mysql_native_password cannot be loaded” 之类的话那更是实锤了插件加载异常。2. 为什么 mysql_native_password 会凭空“消失”这些年 MySQL 的认证策略变化2.1 MySQL 8.0 时期的铺垫默认插件变了老插件还在MySQL 8.0 刚推出的时候默认认证插件就从mysql_native_password换成了caching_sha2_password。但出于兼容性考虑mysql_native_password插件本身仍然被编译在官方发行版里默认也是启用的。也就是说在 8.0 系列里即便你的用户还是老的mysql_native_password认证一般不会报 1524顶多会在客户端连接时看到一些 caching_sha2_password 相关的兼容性提醒。真正让mysql_native_password变得“岌岌可危”的信号其实从 8.0.34 就开始了——官方明确标记它为废弃插件并预告未来版本会移除。可惜当时很多运维人员没当回事毕竟“废弃”到“移除”在数据库领域通常要经历好几个大版本很多人想着怎么也能再撑五六年。2.2 MySQL 8.4 LTS默认关闭状态变成 DISABLED到了 MySQL 8.4 LTS情况发生了实质变化。这个版本虽然还保留着mysql_native_password的插件代码但默认是关闭的。如果你是从 8.0 直接升到 8.4原来那张mysql.user表里大量使用mysql_native_password的账号并不会自动切换认证方式密码哈希也不会自动重算。升级后服务端发现自己有账户需要mysql_native_password插件但这个插件默认不被加载于是一登录就触发 1524。在 8.4 里你如果执行SHOW PLUGINS大概率会看到mysql_native_password的状态是DISABLED而不是完全不存在。这给救急留了一条路详见后面方案一。2.3 MySQL 9.0 及以后插件源码被彻底移出配置开关也救不回来MySQL 9.0 是关键的分水岭。从这一代开始官方发行版直接移除了mysql_native_password插件模块连lib/plugin/mysql_native_password.so这个文件都没有了。这个时候如果再出现 1524想在配置文件里加一行mysql_native_passwordON来“唤醒”插件只会得到插件不存在的错误因为没有本体可供加载。所以很多从 8.4 升到 9.0 的环境如果在 8.4 阶段只是临时开启老插件顶着没有做账号迁移到 9.0 就会遇到第二次同样的 1524。这不是偶然事故而是当年偷的那一步懒要补回来了。2.4 其他容易被忽略的触发源容器镜像参数和精简发行版除了版本升级还有两个场景很容易让人踩坑。第一个是使用 Docker 镜像时自己在启动命令里加了--mysql-native-passwordOFF之类的参数等于主动关掉了这个插件。有些官方镜像或第三方优化镜像甚至默认就在配置文件里写了关闭项换镜像后第一次启动就中招。第二个是某些基于 MySQL 源码二次编译的发行版因为安全合规要求干脆没有编译这个插件。这种情况在国产化数据库环境里不少见排查时要留意当前实例的编译来源。3. 完整排查链路从安全模式进入到定位“遗留用户”3.1 第一步用 skip-grant-tables 绕开认证先把门撬开遇到 1524 时常规登录已经是死路第一步要做的不是改密码而是绕过认证进入服务器内部看插件状态。标准做法是# 先停掉 MySQL 服务 systemctl stop mysqld # 或者用 mysqladmin 关闭前提是当前服务还能连上去 mysqladmin -uroot -p shutdown停掉之后以跳过授权表的方式启动mysqld_safe --skip-grant-tables --skip-networking 这里有个细节我建议一定加上--skip-networking。因为这个启动方式下 MySQL 完全不做访问控制如果不加只要本机网络端口对公网开放任何能连到你 3306 端口的人都可以无密码进库风险极大。加上--skip-networking之后只允许本地 socket 连接更安全。然后直接连进去mysql -uroot注意这时候不需要密码因为权限检查已经被跳过了。3.2 第二步确认插件到底是“不存在”还是“被禁用”进入 MySQL 后第一时间执行SHOW PLUGINS;或者查更细的信息SELECT PLUGIN_NAME, PLUGIN_STATUS, PLUGIN_LIBRARY FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME mysql_native_password;结果会有几种情况查不到该行说明插件没被编译进实例或者动态插件没注册这是 MySQL 9.0 的典型状况。查到了但PLUGIN_STATUS是DISABLED说明插件文件还在只是配置里被关掉了MySQL 8.4 默认就是这样的状态。查到了且状态是ACTIVE那说明插件其实是加载的这时如果还报 1524问题可能出在别的变量上需要继续往下查。同时再看一下系统变量的当前值SHOW VARIABLES LIKE mysql_native_password;如果返回OFF则配置层面确实关闭了插件。3.3 第三步在 mysql.user 里寻找“患者账号”插件状态确认后接着要看有哪些账号正依赖这个插件。执行SELECT user, host, plugin, authentication_string FROM mysql.user WHERE plugin mysql_native_password;这一步决定后续处理范围。如果只有rootlocalhost一个账号那处理起来很轻松。如果是生产库结果可能很长几十个业务账号都绑在老插件上。authentication_string字段也值得看一眼老的mysql_native_password哈希是 40 位十六进制字符串而新的caching_sha2_password哈希以$A$开头两者一眼就能分辨。3.4 第四步翻启动参数和配置文件找到“作案开关”光在库里看还不够还得找出是谁把插件关掉的。常见的检查位置/etc/my.cnf、/etc/mysql/my.cnf、/usr/etc/my.cnfmysqld的启动命令行ps -ef | grep mysqldDocker 场景看docker inspect的Cmd和Entrypoint重点搜索mysql_native_password字段。如果配置文件里写了[mysqld] mysql_native_password OFF那基本就是它把插件状态改成了 DISABLED。还有一点要注意8.0 时代的配置里常见的default_authentication_pluginmysql_native_password到了 8.4 以后已经不被推荐了8.4 引入的是authentication_policy这条老配置存在容易让人误以为“我明明配了 native怎么还是加载不了”。4. 救急路线重新加载插件到底划不划算4.1 8.4 的临时方案配置开关重新打开如果你的实例是 MySQL 8.4并且排查确认插件只是因为配置被关闭而处于 DISABLED 状态那最简单的救急办法就是在配置文件的[mysqld]段加上[mysqld] mysql_native_password ON重启 MySQL 服务后插件会恢复为 ACTIVE原本使用老认证插件的账号就可以正常登录了。这种方式我在测试环境和部分低峰期的生产库上用过确实是见效最快的“止血”方案。4.2 尝试 INSTALL PLUGIN 时要注意的坑有些资料会让你在运行时直接执行INSTALL PLUGIN mysql_native_password SONAME mysql_native_password.so;这个命令只适用于插件文件存在、但尚未注册到插件表的情况。在插件本来就存在且只是被 DISABLED 的场景下执行会报错大意是插件已存在。反过来在 MySQL 9.0 上执行则会提示找不到 so 文件意思就是源码和文件都没了此路不通。所以INSTALL PLUGIN最有用的是那些“精简编译版”的 MySQL 8.0 环境插件文件被删了但plugin_dir里还能找到其他参考。可以先用SHOW VARIABLES LIKE plugin_dir看看插件目录在哪再用系统命令确认这个 so 文件是否真的存在。4.3 为什么我不建议长期走这条路线把mysql_native_password重新打开等于把旧的认证机制又请回来了这样做有两个隐患第一这个插件已经在安全上落后很多。mysql_native_password的密码哈希算法强度不如caching_sha2_password在安全审计里属于重点被点名对象。一旦开启审计报告可能直接给你标红。第二版本越新越靠不住。如果某天你再做一次大版本升级从 8.4 升到 9.0这个配置项会直接失效因为插件源码头里已经删干净了。到时候还得重新走一遍当前的排查流程相当于把坑踩第二遍。所以说打开插件顶多是过渡方案不能作为最终归宿。尤其当你发现mysql.user里只有两三个账号的时候还不如直接切到新认证方式一了百了。5. 彻底根治把账号迁移到 caching_sha2_password5.1 为什么必须改账号认证方式而不是只改配置说到底配置开关只能改变“服务器有没有加载插件”不能改变“用户表中的账号绑定在哪个插件上”。只要账号的plugin字段还是mysql_native_password一旦插件消失或者被禁用这个账号依然是废的。只有把账号的认证方式真正切换到caching_sha2_password才算彻底解除 1524 的复发可能。另外一个经常被忽略的点老插件的密码哈希和caching_sha2_password的密码哈希并不是同一个算法算出来的不能把老的authentication_string直接复制到新账号下。这意味着迁移过程中必然要重置密码。你无法保留用户原来的密码明文更无法“无缝”地保留原哈希。这个约束要在项目启动前跟业务方说清楚否则他们以为运维改个配置账号密码就不会变结果一上线发现所有应用都在报密码错误。5.2 单账号迁移的标准操作如果只是root或者其他少数几个账号需要处理操作命令很直接。在刚才的 skip-grant-tables 模式下先执行FLUSH PRIVILEGES;这一步很关键。因为我们是用跳过授权表模式进来的如果不先刷新权限紧接着的ALTER USER会被拒绝执行报错信息通常是不允许在当前模式下修改。刷新之后再做ALTER USER rootlocalhost IDENTIFIED WITH caching_sha2_password BY 这里填最强者密码;命令执行完可以验证一下SELECT user, host, plugin FROM mysql.user WHERE user root AND host localhost;确认plugin列已经变成caching_sha2_password之后重启 MySQL 到正常模式再用新密码登录1524 就消失了。5.3 大量账号批量迁移的脚本思路生产环境很少只有一两个账号几十个业务账号密密麻麻绑在老插件上是常态。这时候手工一条条改不现实我一般用 SQL 批量生成修改语句再统一执行。先生成清单SELECT user, host FROM mysql.user WHERE plugin mysql_native_password;然后针对每个账号生成一条带新密码的ALTER USER语句。为了不让密码都变成同一个可以用随机串。比如SELECT CONCAT( ALTER USER , user, , host, IDENTIFIED WITH caching_sha2_password BY , SUBSTRING(MD5(RAND()), 1, 16), ; ) AS alter_sql FROM mysql.user WHERE plugin mysql_native_password;把查询结果导出来逐条执行。但我必须提醒一点用这种方式生成随机密码执行完之后你需要把每个账号对应的新密码记录下来交给业务方。脚本只是手段密码的交接和管理才是大头。如果公司有密码管理系统就让生成密码的过程和收尾记录都纳入系统里走别图省事贴个 Excel 到处传。真实做法是先在测试库完整跑一遍确认密码生成逻辑、账户清单、执行顺序都没问题再挑业务低峰期在生产库操作并且操作前做好备份。5.4 迁移完成后的验证动作迁移不是执行完命令就算完事的还要做一轮完整性校验确认mysql.user表里plugin mysql_native_password的记录数为 0。选几个核心业务账号模拟客户端连接确认新密码能通过。如果原来有按密码哈希做分区的监控脚本注意同步更新。如果 MySQL 版本是 8.4 且你之前打开过mysql_native_password ON迁移完成后可以把这个配置项删掉再重启一次确认服务完全依赖caching_sha2_password正常跑。6. 迁到 caching_sha2_password 之后真正的战场是客户端兼容性6.1 为什么换了个认证插件客户端就开始连不上了很多团队栽在这一步服务器的 1524 消除了账号也切到caching_sha2_password了结果第二天业务方反馈一大片应用连不上数据库报错五花八门。问题出在驱动对caching_sha2_password协议的支持上。caching_sha2_password的完整认证流程比老插件复杂。它先用 SHA256 做一次快速认证如果这套流程走不通就需要通过安全通道做完整密码验证。如果连接没有启用 SSL/TLS服务端会把 RSA 公钥发给客户端客户端用公钥加密密码后传过来。这个环节要求客户端驱动支持 RSA 公钥获取和加密老驱动往往卡在这里。6.2 不同语言的常见驱动表现和调整方式我用几个主流客户端举例方便你对号入座客户端/驱动兼容状况常见调整MySQL 8.0 官方命令行客户端原生支持无需额外配置JDBC Connector/J 8.0.9 及以上原生支持低版本需升级驱动JDBC 老版本5.x不完全支持加allowPublicKeyRetrievaltrue但仍建议升级PHP mysqli / PDOmysqlnd 驱动7.4 原生支持检查是否走 mysqlnd 而非 libmysqlclientPython PyMySQL新版本支持保持版本更新Python mysqlclient兼容性随版本变化确保使用新版比如 Java 应用遇到无法连接时要么把 Connector/J 升级到 8.0.9 以上要么在连接串里加上jdbc:mysql://host:3306/db?userxxxpasswordyyyallowPublicKeyRetrievaltrueuseSSLfalse但allowPublicKeyRetrievaltrue有个隐患它允许客户端自动向服务器请求 RSA 公钥这相当于降低了中间人攻击的门槛。如果网络环境不是完全可信我更建议开useSSLtrue用 TLS 加密通道代替 RSA 公钥传输。6.3 如果驱动真的老到升不了级怎么办总有那么一两个“老古董”系统驱动版本停留在很多年前短期内根本升不了级。这时候我的底线做法是仅给那个实在改不了的旧系统保留一个单独的账号临时使用mysql_native_password其他所有账号一律切到caching_sha2_password。前提是实例版本还支持这个插件8.4 临时开、8.0 默认开并且做好安全补偿比如限制这个账号只能从内网固定 IP 连接、只能访问指定数据库、密码策略调强。附带一句如果实例已经是 9.0连这个“临时保留”的选项都没有了。到时候唯一的出路就是升级客户端没有第二条路。所以业务系统里的数据库驱动版本管理真的应该纳入日常巡检别等数据库版本逼着你升级时再手忙脚乱。7. 复盘我在处理 1524 时踩过和看见别人踩过的坑7.1 千万别在 skip-grant-tables 模式下直接改密码我第一次处理这个问题时进入 skip-grant-tables 模式后直接执行ALTER USER ... IDENTIFIED BY 新密码结果 MySQL 直接拒绝说当前模式下不允许这种操作。后来才知道必须先执行FLUSH PRIVILEGES让权限系统重新初始化然后才能走正常的账号修改流程。这个顺序写进方案文档里能帮你少一次怀疑人生的机会。7.2 “先升级再排查”顺序不对差点把生产库搭进去有个项目曾经直接把 8.0 的库升到 9.0升完才发现应用大面积连不上。当时所有人都以为是升级失败急着回滚最后排查才发现就是老认证插件被移除导致的。这件事给我的教训是大版本升级前先统计mysql.user表里各认证插件的账号数量如果发现mysql_native_password占比超过一定量就得先做账号迁移做好驱动兼容性验证再动升级的念头。适合放在升级前执行的检查语句SELECT plugin, COUNT(*) AS account_count FROM mysql.user GROUP BY plugin;一条 SQL 看清整个库的认证方式分布。7.3 升级前的检查清单如果你正在规划 MySQL 大版本升级我建议把下面这套清单在测试环境先跑一遍统计mysql.user中plugin字段分布列出所有mysql_native_password账号。确认所有业务组件的数据库驱动版本逐项对照目标版本 MySQL 的认证插件兼容表。在测试环境完整模拟一次升级把mysql_native_password配置设为关闭状态然后尝试所有核心应用连接。对每个依赖老插件的账号提前规划新密码走正式的密码变更流程。检查应用的连接池配置注意有些连接池会在初始化时做探活探活语句也要兼容新认证方式。这些看起来琐碎但每一步都是在提前排雷。1524 看起来只是一个小错误但它背后牵涉的是数据库认证体系的代际更替。早一点把账号迁移到caching_sha2_password早一点升级驱动总好过在某次升级后的凌晨三点被报警电话叫起来面对一群连不上的应用。我在处理完之后最大的体会就是这种错误一次都不要犹豫别想着用配置开关拖时间拖到最后还是要还账的。