接手 MySQL 项目这些年Public Key Retrieval is not allowed 大概是我在 DBeaver 用户群里被问过最多的一个报错。上周五下午我帮同事在 DBeaver 里新建连接指向一台 MySQL 8.0 实例账号密码明明没错端口也通首次测试连接时甚至弹了成功提示可一旦点开表准备查数据就立刻弹出一行英文报错Public Key Retrieval is not allowed。我当下没有去怀疑账号或权限而是马上想到了 MySQL 8 默认认证插件与 JDBC 驱动之间的那次握手差异。DBeaver 用户以及所有通过 JDBC 直连 MySQL 8 的开发者都可能在某个版本组合里撞上这个错。这个错误最烦人的地方在于它不是传统的 Access denied不会让你第一时间想到认证方式反而会让人误以为是驱动坏了、权限丢了或者表结构有问题。这篇文章我会把这个报错从原理到解法完整拆开覆盖 DBeaver 图形界面操作、JDBC URL 手动配置、MySQL 服务端认证插件这几个层面后面直接照着做就能解决。1. 现场还原什么样的连接最容易撞上这个错误1.1 报错文本和触发时机先精确描述一下报错的样子。在 DBeaver 里通常不是点击“测试连接”按钮时报错而是会在你真正执行查询、展开表列表或者查看表数据时弹出对话框标题一般是 Database Error核心文本只有一行Public Key Retrieval is not allowed配合 DBeaver 的详细日志可能还会看到类似这样的一段java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed这里有两个关键信息异常类型是 SQLNonTransientConnectionException意思是“非临时性连接异常”不是网络抖动不是超时重试能解决的错误文本直接点名了公钥检索被禁止说明认证流程已经走到了密码加密传输那一步只是驱动主动放弃了。印象里 MySQL 5.7 时代极少见到这个错但 MySQL 8.0 大量普及之后这个报错在 DBeaver 社区里几乎是日经问题。1.2 最容易踩坑的环境组合我观察到的触发条件相当统一只要同时满足下面几条基本逃不掉服务端是 MySQL 8.0 及以上版本客户端通过 JDBC 驱动访问数据库DBeaver 本质上就是 JDBC 客户端连接走的是 TCP/IP且没有启用 SSL 加密通道连接属性里没有显式设置 allowPublicKeyRetrievaltrue。反过来如果你用的是 mysql 命令行客户端或者数据库还是 MySQL 5.7那就很少会见到这个报错。很多团队是在把数据库从 5.7 迁移到 8.0 之后才开始大面积踩坑的因为应用和 DBeaver 的连接配置都没改数据库升级完突然就全线报错。下面这张表可以快速对照定位环境维度典型配置是否容易触发这个报错数据库版本MySQL 5.7 及更早基本不触发数据库版本MySQL 8.0 及以上高概率触发访问方式DBeaver 或其他 JDBC 工具高概率触发访问方式mysql 命令行客户端不触发连接通道非 SSL 的 TCP/IP高概率触发连接通道SSL 加密连接不触发如果你现在的连接配置正好落在“MySQL 8.0 DBeaver 非 SSL”这个三角形里那这个报错就是标配不是你的环境出了特殊问题。1.3 为什么连接测试通过一打开表却报错这个“先通过后报错”的时序让很多人困惑。原因在于 DBeaver 建立连接时虽然完成了基础握手但未必立刻走完 caching_sha2_password 的完整公钥交换流程。当你打开表结构、执行普通查询时驱动才会真正向服务器发起带密码验证的请求这时服务端发现自己处于非 SSL 通道便要求客户端先获取 RSA 公钥而 JDBC 驱动默认不允许自动获取公钥于是立即抛出异常。换句话说你不是连不上数据库而是“连接被客户端自己在安全策略层面中止了”。所以此时去 MySQL 端看 error log基本什么都看不到数据库也没有拒绝任何请求。这个特征如果理解不到位排查方向很容易跑偏很多人在这里浪费好几个小时。2. 错误根因caching_sha2_password 与 JDBC 驱动的一次安全拉扯2.1 MySQL 8 为什么把默认认证插件换成 caching_sha2_passwordMySQL 5.x 时代默认的认证插件叫 mysql_native_password。它最大的优势是简单、兼容性好几乎所有客户端不用额外配置就能连上。但它的问题也很明显密码校验过程基于 SHA1 散列算法强度在现代硬件面前已经不够看而且对密码在传输链路上的保密能力偏弱容易出现碰撞攻击和重放风险。MySQL 8.0 开始把默认认证插件换成了 caching_sha2_password。这个插件名字里藏着两个关键词sha2 说明它走的是 SHA-256 级别散列强度比 SHA1 高一大截caching 说明服务端会对认证结果做缓存高频登录时能大幅减少重复计算。密码哈希的存储方式也更安全即使数据库文件被拖走从散列逆推出原始密码的难度也高得多。代价就是兼容性。新插件引入了一套新的认证握手流程老驱动不认识甚至连一些老的图形客户端都要升级才能适配。MySQL 官方其实早就预料到了这一点所以 8.0 里同时保留了 mysql_native_password 插件只是默认不再使用。可惜很多团队在升级数据库时没有重新审视客户端的兼容性于是 DBeaver 这类基于 JDBC 的工具就开始集中爆发问题。2.2 allowPublicKeyRetrieval 这个参数到底管什么要弄懂 allowPublicKeyRetrieval 的作用得先知道 caching_sha2_password 在“非 SSL 连接”下是怎么传输密码的。整个流程大致是这样客户端向服务器发起连接声明用户名服务器发现该账号使用 caching_sha2_password且当前连接没有开启 SSL服务器向客户端返回一个 RSA 公钥并生成一个随机盐值客户端使用该公钥把“密码加盐之后的散列值”加密再送回服务器服务器用私钥解密验证结果决定是否允许登录。也就是说客户端必须先主动向服务器索取公钥。但 MySQL Connector/J 出于安全考虑默认不允许客户端自动获取服务器公钥也就是 allowPublicKeyRetrievalfalse。一旦连接里没有预置公钥又没启用 SSL客户端就直接停止认证抛出 Public Key Retrieval is not allowed。这个默认值的设计逻辑是如果客户端盲目接受服务器下发的公钥那么在不可信链路上中间人完全有可能伪造服务器下发一个自己的公钥然后骗取客户端用这把公钥加密密码。一旦攻击者拿到密文再配合自己的私钥密码就等于裸奔了。所以 JDBC 驱动把“自动索取公钥”这个动作设成默认禁止相当于强制要求用户显式确认自己信任这条网络链路。2.3 SSL 连接为什么能绕开这个报错如果你启用了 SSL 连接那么客户端和服务器之间在更早的握手阶段就已经协商好了加密通道后续传输全部在 TLS 隧道内完成。密码本身已经有通道级加密保护就不再需要额外用 RSA 公钥加密密码。所以 useSSLtrue 之后即使 allowPublicKeyRetrieval 保持默认 false也不会触发这个报错。可以这么理解非 SSL 连接就像走普通快递寄贵重物品你要自己找一把锁把物品锁起来还得去快递公司领钥匙SSL 连接则像是走武装押运专车全程有保安护送你不需要额外加一把锁。JDBC 驱动的态度是你去领钥匙这件事存在风险所以我默认不让你去但如果你坐的是武装押运车那就不用领钥匙自然也没人拦你。这就是为什么网上提到这个报错时给出的解法往往有两类一类是开启 allowPublicKeyRetrieval另一类是配置 SSL 相关参数。两者本质上都是在解决“密码如何在非可信通道里安全传输”的问题只是角度不同。接下来我把具体操作分开讲。3. 解法一在 DBeaver 里放开公钥检索权限推荐日常开发使用3.1 操作路径编辑连接 → 驱动属性如果你的环境是本地开发机、内网服务器或者测试库链路可信度比较高那我最推荐直接放行公钥检索。DBeaver 的配置入口通常在连接的“驱动属性”面板里。具体步骤在 DBeaver 左侧数据库导航树里找到目标连接右键点击选择“编辑连接”在弹出的窗口左侧找到“驱动属性”一栏不同版本可能叫“连接属性”或者“连接设置”但最终都要进入以属性表格为核心的区域在属性列表底部找到空白的输入行或者在空白处点击右键选择“新增属性”属性名填写 allowPublicKeyRetrieval值填写 true点击“确定”保存然后回到数据库导航树右键连接选择“重新连接”。能看到一个新的属性行说明你已经配置成功了。重新连接后再随便打开一个表查看数据会发现这个报错已经消失。我自己在多个版本的 DBeaver 上测试过这个属性名大小写是固定的不要写成 Allowpublickeyretrieval 或者 allowPublicKeyRetrivalJDBC 驱动对属性名是严格匹配的。如果你用的是较新的 DBeaver 版本界面排布可能和旧教程截图不一样。老版本里“驱动属性”直接显示在左侧列表顶层新版本则被收纳在“连接设置”下方的折叠区里需要点开才能看到。思路一致找到那个能对 Connection Properties 或 Driver Properties 进行增删的地方不需要死磕菜单名。3.2 如果你习惯手动拼 JDBC URL有些读者不喜欢点鼠标配置面板更习惯直接看 JDBC URL。DBeaver 同样支持这种操作。在“编辑连接”窗口的驱动属性区域底部通常会展示当前连接对应的 JDBC URL。你可以在 URL 末尾手动追加参数典型写法类似jdbc:mysql://127.0.0.1:3306/testdb?allowPublicKeyRetrievaltrueuseSSLfalseserverTimezoneAsia/Shanghai这里要特别提醒一个坑URL 参数和驱动属性面板里的同名属性不要同时配置或者至少保证值一致。我见过有同事在 URL 里加了 allowPublicKeyRetrievaltrue又在驱动属性面板里保留了 allowPublicKeyRetrievalfalse结果查来查去仍然报错。两处配置冲突时驱动属性面板的优先级往往高于 URL 参数最终生效的是 false改了等于没改。最简单的方式是只保留一处配置。另外MySQL 8 对应的 JDBC 驱动类名通常是 com.mysql.cj.jdbc.Driver而 MySQL 5.x 时代常用的是 com.mysql.jdbc.Driver。DBeaver 一般会自动选择正确驱动但如果你在某些连接配置里手动指定过驱动类记得确认没有被老版本覆盖。3.3 这个方案的安全边界为什么说这个方案更适合“日常开发使用”因为它本质上是让你主动信任服务器下发的公钥而这个信任没有任何额外的验证机制。在内网、本机、测试环境里风险非常低因为网络链路基本可控中间人很难插进来。但如果你是通过公网直连数据库或者网络链路中有大量陌生网关、代理再或者涉及生产库的变更那就应该慎重。更稳妥的公网访问方式是把 useSSL 设为 true并配合 sslModeVERIFY_CA同时把服务器 CA 证书加入客户端信任库。DBeaver 里同样在驱动属性面板配置。很多云数据库实例默认已经开好了 SSL客户端拿到 CA 证书后一配就通。相比 allowPublicKeyRetrievaltrue这是一条更符合安全要求的路径只是初期配置成本更高。4. 解法二把 MySQL 账号的认证插件换回 mysql_native_password4.1 什么时候必须走这条路方案一虽然简单但有一个前提你有权限修改 DBeaver 的连接配置。现实里经常出现没这个权限的情况比如连接配置由运维平台统一下发业务代码里写死了 JDBC URL或者数据源配置由中间件统一管理不允许个人随意改。这时与其到处找连接配置不如直接在 MySQL 侧把账号的认证插件换回 mysql_native_password。另一种典型场景是老客户端太多。公司里可能有跑了好几年的定时任务、报表系统、老业务模块它们内置的 JDBC 驱动从来没升级过根本不认识 caching_sha2_password 这套新流程也未必支持 allowPublicKeyRetrieval 参数。如果逐个服务去升级驱动工作量巨大团队未必愿意排期。这种情况下把账号插件一次性降回旧协议所有老客户端立刻全部恢复是投入产出比最高的方案。4.2 具体 SQL 与注意事项先查一下目标用户当前用的认证插件SELECT user, host, plugin FROM mysql.user WHERE user root;正常输出里plugin 那列应该是 caching_sha2_password。把它改成 mysql_native_password 的语句如下ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码; FLUSH PRIVILEGES;执行完之后这个账号的密码也会被重置成你指定的新密码。如果这个账号在多个连接串里被使用你需要同步更新所有使用方否则后面会出现 Access denied 之类的连锁问题。还需要特别注意 host 的匹配范围。很多生产库给应用用的账号是 app%而不是 rootlocalhost修改时一定要按实际 host 执行。如果一台库上同时存在 localhost 和 % 两条用户记录单独改其中一条并不会影响另一条排查时容易以为 SQL 没生效。改完之后可以用下面的 SQL 复查SELECT user, host, plugin FROM mysql.user WHERE user root;看到 plugin 变成 mysql_native_password才算修改成功。整个过程不需要重启 MySQL 服务因为 ALTER USER 是动态生效的FLUSH PRIVILEGES 是为了确保权限缓存刷新这一步在 MySQL 8 里很多时候不是必须的但执行一下更保险。4.3 两个方案怎么选我直接给一张决策对照表大家按自己的处境选就好对比维度改 DBeaver 参数改 MySQL 账号插件改动范围单个客户端数据库账号全局影响面当前工具、当前项目所有使用该账号的客户端风险程度低随时可撤销中影响面更广适合场景个人开发机、测试环境老客户端多、连接配置不可改对客户端要求支持该参数即可需要兼容 mysql_native_password 协议长期趋势契合 MySQL 8 安全方向属于临时兼容手段如果只是你自己在 DBeaver 里连库方案一就够了。如果是团队共用的系统账号我建议优先评估允许该账号使用 mysql_native_password 的安全性影响确认没有合规问题后再执行。生产库尤其要谨慎能不动认证插件就不动尽量用 SSL 或者升级客户端解决。5. 排查与避坑改完之后还在报错怎么办5.1 驱动版本是不是旧了改了 allowPublicKeyRetrieval 之后仍然报错第一个要排查的是驱动版本。DBeaver 内置的驱动列表虽然做了适配但不会总跟着 MySQL Connector/J 的最新版本走。如果内置驱动版本过旧它可能不认识这个参数也可能对 caching_sha2_password 的握手流程支持不完整。更新驱动的方法很直接菜单栏打开“数据库” → “驱动管理器”找到 MySQL 驱动点击右侧的“更新”或“下载/更新”按钮。DBeaver 会尝试联网下载最新的驱动 JAR。如果所在网络环境不允许访问外网还可以离线操作在另一台能联网的机器上把对应版本的 Connector/J JAR 包下载回来然后在驱动设置里点击“添加文件”或者“注册驱动”手动指定本地 JAR 路径。更新完驱动之后别忘了彻底重启一次 DBeaver。某些版本的 DBeaver 在热更新驱动后并不会立刻替换已加载的类只靠“重新连接”不够必须重启整个进程。这一条实操中特别容易踩很多人更新完驱动还在报错就是因为没有重启。5.2 参数大小写、连接缓存、工作区干扰参数名的大小写必须精确。allowPublicKeyRetrieval 是 JDBC 驱动严格匹配的属性名多一个字母、少一个字母、大小写不对都会导致参数静默失效。JDBC 参数解析不像 Windows 文件名那样对大小写宽容请务必直接复制教程里的写法不要手打。如果参数配置没问题但连接还是旧状态通常就是缓存问题。DBeaver 的工作区会自动保存连接状态有时你改了连接属性它却还沿用缓存里的旧连接信息。我的习惯是改完驱动属性后右键断开连接再关闭 DBeaver重新打开之后重新连接。如果这样还不行就把这个连接配置整个删掉重新建一个输入同样的 IP、端口、账号密码往往一下子就通了。5.3 命令行能连、工具连不上的场景排查时很容易遇到一个矛盾现象在服务器上执行 mysql -uroot -p 能正常登录DBeaver 却一直报 Public Key Retrieval is not allowed。有人会因此怀疑是 DBeaver 的配置问题或者是 IP 白名单限制进而去翻防火墙和安全组。其实这两个结论都不对。mysql 命令行客户端对 caching_sha2_password 的支持是原生内置的它能自动走完整个公钥交换流程所以命令行不受 allowPublicKeyRetrieval 参数限制。而 DBeaver 依赖的 JDBC 驱动默认对公钥索取持保守态度这是客户端栈层面的差异。命令行能连只能证明数据库服务正常、账号权限正常并不能说明 JDBC 链路的配置没有问题。遇到这个场景请直接检查驱动属性不要白白排查网络。5.4 这个报错不只属于 DBeaverPublic Key Retrieval is not allowed 并不是 DBeaver 独有的现象。Navicat、JetBrains 系的数据库插件、Spring Boot 项目里的 HikariCP、Tomcat JDBC Pool只要是基于 MySQL Connector/J 的访问链路都可能出现完全相同的报错。区别只是配置入口不同。比如在 Spring Boot 的 application.yml 里你需要在 JDBC URL 后面追加参数spring: datasource: url: jdbc:mysql://127.0.0.1:3306/testdb?allowPublicKeyRetrievaltrueuseSSLfalseserverTimezoneAsia/Shanghai在 Navicat 里则是通过“连接属性”面板添加同名参数。核心逻辑完全一致只要 JDBC 驱动认为“非 SSL 通道 未允许获取公钥”就会拒绝继续认证。你只要理解了这一层无论换什么工具都能快速定位。6. 一点个人建议与实测体会最后说几句实际操作层面的建议。我在自己的开发机上默认都把 allowPublicKeyRetrieval 设为 true因为开发环境的网络链路相对可控这样做能省掉很多重复报错。但生产环境我不会乱动认证插件更倾向于用 SSL 通道解决因为生产库的账号往往是多个团队共用的改认证插件影响面不可控。遇到 DBeaver 改完参数不生效的情况我通常按这个顺序处理先确认参数名大小写再确认驱动版本然后重启 DBeaver最后删除连接重建。大多数疑难杂症都能在这一套流程里解决真正需要去改数据库账号插件的情况反而不多。希望这篇记录能帮你少走一段弯路。