
前两天准备把一台开发机的 MySQL 从 5.7 升到 8.0升级完顺手打开 DBeaver 想连上去看下数据表结构结果“连接测试”直接甩给我一行红字Public Key Retrieval is not allowed。紧接着就是一大段英文堆栈。第一次遇到这个报错的人第一反应多半是“我密码是不是写错了”然后反复重输密码折腾十分钟发现根本没用。其实这个报错跟密码一毛钱关系都没有是 MySQL 8.0 的默认认证机制变了而 DBeaver 用的 JDBC 驱动出于安全考虑默认不允许自动获取服务器公钥两边一冲突就报错。这个问题在 DBeaver 连 MySQL 8.0 的场景里几乎人人都会撞上一次网上答案零零散散有人让你改驱动属性有人让你改 MySQL 用户还有人直接让你换驱动版本新手往往不知道该听谁的。这篇文章我把三种可行方案从头到尾捋一遍包括背后的原理、具体操作步骤、各自的适用场景以及改完之后仍然连不上的排查思路。不管你是 DBA、后端开发、测试还是刚接触数据库的新手照着做完基本都能解决。1. 先搞懂报错原因MySQL 8.0 的认证机制变化1.1 报错现场什么情况下会触发先说说我遇到这个问题的现场。我的环境是DBeaver Community 版具体版本号已经记不清但肯定是 21.x 以上的版本MySQL 8.0.28JDBC 驱动是 DBeaver 自带的 mysql-connector-java。连接方式是最普通不过的 TCP/IP用的用户是 roothost 是 localhost。点击“测试连接”后DBeaver 弹出的错误信息大致如下Public Key Retrieval is not allowed点开详情还能看到类似这样一段java.sql.SQLException: Public Key Retrieval is not allowed at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129) ...如果你和我一样用的是 5.x 版本的 MySQL这个错误是绝对不会出现的。从 MySQL 8.0 开始默认的认证插件从 mysql_native_password 换成了 caching_sha2_password这一换连带着 JDBC 客户端的连接行为也变了。另外说一句这个问题不只在 DBeaver 里出现。只要是基于 JDBC 的客户端比如 IntelliJ IDEA 自带的 Database 工具、SQuirreL SQL、DataGrip 等都有可能遇到同样的报错。区别只是部分工具版本比较新已经在默认参数里帮你开了公钥检索所以不报错而 DBeaver 的默认配置比较保守就把这个错误暴露出来了。1.2 caching_sha2_password 和公钥检索到底是怎么回事要理解这个报错得先知道 MySQL 8.0 在认证环节做了什么改动。MySQL 5.7 及更早的版本默认使用 mysql_native_password 插件密码校验方式是 SHA1 加盐哈希客户端在认证时直接把这个哈希结果发给服务器整个过程不需要额外的密钥交换。这种方式简单粗暴但安全性已经跟不上时代尤其是碰撞攻击和暴力破解的成本越来越低。MySQL 8.0 引入了 caching_sha2_password 插件并把它设为默认。它同样基于 SHA256但密码不会明文传输而是先通过服务器的 RSA 公钥加密再发送到服务器端解密校验。问题就出在这个“RSA 公钥”上。如果客户端和服务器之间没有走 SSL/TLS 加密连接那么 caching_sha2_password 在认证阶段会经历一个“获取公钥”的步骤。这个公钥的获取有两种方式一是服务器在握手过程中主动把公钥发给客户端二是客户端主动向服务器发起请求索取公钥。而 MySQL 的 JDBC 驱动mysql-connector-java在连接参数里有一个开关叫 allowPublicKeyRetrieval控制的就是“是否允许客户端主动向服务器索取公钥”。这个参数默认是 false。当它为 false连接又没启用 SSL服务器也不会在握手时自动下发公钥于是驱动直接抛出 Public Key Retrieval is not allowed 来阻止连接继续。一句话概括不是密码错了是认证过程中需要拿一把公钥来加密密码但 JDBC 驱动默认不让你去拿。1.3 为什么 JDBC 驱动要关闭这个开关你可能会问既然服务器可以提供公钥那 JDBC 驱动默认允许不就行了何必搞这么一出这里涉及中间人攻击的考量。如果客户端在建立连接时不加验证地去获取服务器公钥那攻击者可以在网络链路上假装自己是目标服务器提前给客户端一个自己的公钥。客户端用这把假公钥加密密码攻击者在另一边截获后用私钥解密密码就泄露了。所以 JDBC 驱动把这个选项设计成默认关闭属于“默认最安全”的取舍。你要明确告诉驱动“这台服务器我是信的”或者干脆换一条带 SSL 加密的通道它才肯放开公钥检索。明白了这层逻辑后续几种解法就很好理解了要么手动打开公钥检索的开关要么让服务器端改用旧版认证方式绕开 RSA 公钥交换要么直接走 SSL 加密连接。2. 最快解法在 DBeaver 里打开公钥检索2.1 图形界面操作步骤如果你是开发环境自查或者公司内网连接测试环境最省事的方法就是在 DBeaver 连接设置里把 allowPublicKeyRetrieval 参数打开。注意不同版本的 DBeaver 界面布局有细微差异但大体路径一致。我的操作步骤是这样的在 DBeaver 左侧“数据库导航器”里找到你配置的那个 MySQL 连接。右键点击连接名称选择“编辑连接”。在弹出的连接设置窗口里找到“驱动属性”标签页英文版是 Driver properties。在属性列表里找到 allowPublicKeyRetrieval如果看不到可以直接在上方的搜索框里输入 public key 快速定位。把这一项的值从默认的 false 改成 true。点击“确定”保存再重新点“测试连接”。如果你用的 DBeaver 版本较新在“连接设置”页面的“SSL”标签页里也可能直接有一个勾选项叫“Allow public key retrieval”勾上它等价于修改 allowPublicKeyRetrievaltrue效果完全相同。改完之后再次测试连接一般就能顺利通过。我在本机实测下来只要这一步改了连接基本秒过不再弹任何报错。2.2 手动编辑 JDBC URL 的方式如果你没法通过图形界面改或者你用的是其他基于 JDBC 的客户端那就直接编辑连接 URL在末尾追加参数也行。以 DBeaver 为例在“编辑连接”窗口的“主要”标签页里通常能看到“JDBC URL”这个字段。如果界面上是隐藏的可以点“编辑驱动设置”或者直接切换到手动配置模式。URL 最终的样子类似jdbc:mysql://127.0.0.1:3306/your_database?allowPublicKeyRetrievaltrueuseSSLfalse这里我额外加了一个 useSSLfalse原因是如果不明确指定 SSL 行为驱动可能默认尝试协商 SSL某些场景下会引来额外报错或者告警。不过要注意useSSLfalse 和 allowPublicKeyRetrievaltrue 一起使用相当于明确告诉驱动我不走加密通道但允许我去服务器拿公钥。在可信内网环境没问题但在公网环境请谨慎后面第四部分我会详细说 SSL 的事。2.3 这个操作背后的代价和注意点allowPublicKeyRetrievaltrue 不是万能的它有一个安全隐患值得你记住开启后客户端会无条件接受服务器返回的公钥并用来加密密码。如果连接链路上存在恶意节点它有机会冒充服务器诱导客户端用它的公钥加密密码从而窃取密码内容。所以我的建议是本机开发、公司内网、测试环境放心用。生产环境或者跨公网连接尽量别开应该优先考虑 SSL 或修改服务器端认证方式。如果你在一个多人共用的网络环境比如咖啡馆 WiFi、酒店网络里远程连数据库开这个参数等于把密码明文送给潜在攻击者去解密。DBeaver 这个参数是保存在连接配置里的换一台电脑、换一个工作空间之后需要重新设置。旧版本里修改后记得点右下角的“应用”按钮否则可能没保存成功。3. 另一条路把 MySQL 用户认证插件改回旧版3.1 查看和修改认证插件对于不想动客户端参数、希望在服务器端一次性解决的人可以把目标用户的认证插件改回 mysql_native_password。这样客户端不需要走 RSA 公钥交换而是用旧版 SHA1 校验方式完成认证问题也就消失了。这个操作需要先能通过其他方式登录 MySQL比如命令行客户端。步骤如下先用命令行登录 MySQLmysql -u root -p登录后查看当前各用户的认证插件SELECT user, host, plugin FROM mysql.user;你会看到类似这样的结果---------------------------------------------------- | user | host | plugin | ---------------------------------------------------- | root | localhost | caching_sha2_password | | mysql.sys | localhost | caching_sha2_password | | deer | % | caching_sha2_password | ----------------------------------------------------接着把需要修改的用户改为 mysql_native_passwordALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码; FLUSH PRIVILEGES;如果你用的是远程连接主机名部分是 ip 或 %那就要改成对应的 host比如ALTER USER app_user% IDENTIFIED WITH mysql_native_password BY 你的密码;改完再用 DBeaver 连接你会发现不需要勾选 allowPublicKeyRetrieval 也能连上。3.2 一个越来越明显的坑新版 MySQL 已经移除旧插件不过这里我必须提醒一句mysql_native_password 在 MySQL 8.0 里能用但不代表在 8.0 的所有小版本里都能一直用下去。从 8.0.34 开始MySQL 在用户认证相关的日志里会对 mysql_native_password 给出弃用警告。更关键的是从 MySQL 9.0 开始这个插件已经被彻底移除了。如果哪一天你升级到 MySQL 9.x再想用这招就没戏了。到时候服务器端根本不会加载 mysql_native_password 插件ALTER USER 直接报错。所以我的判断是这条路短期可用适合现有业务系统里已经大量使用 mysql_native_password、一时半会儿改不动客户端的团队。但如果你的数据库是从零开始搭建或者你还在评估长期方案我建议不要为了省事把所有用户都改成这个旧插件。迟早都要迁回 caching_sha2_password不如现在就适应它用方案一或者方案四来解决问题。3.3 两种方案的适用场景对比这里直接列一个对比表方便你根据实际情况做决定。对比项方案一allowPublicKeyRetrievaltrue方案二改回 mysql_native_password操作位置客户端 DBeaver 连接配置服务器端 MySQL 用户设置改动范围每次连接单独配置全局生效所有客户端都会受影响安全隐患有中间人攻击风险旧版认证算法安全性相对更低兼容性适用于 MySQL 5.7 到 9.x 全系列不适用 MySQL 9.0适用场景开发环境个人电脑快速连库遗留系统统一迁移客户端版本受限的场景长期可维护性高参数本身没有弃用计划低MySQL 官方已明确淘汰路线我个人处理线上问题时90% 的情况都直接用方案一让开发同学在 DBeaver 里勾一个参数就完事不用动服务器。只有遇到那种“服务器端必须强制使用 caching_sha2_password”的安全合规要求时才去考虑改服务器或者做 SSL。4. 更稳妥的姿势直接上 SSL4.1 连接参数里启用 SSL回到本质问题caching_sha2_password 之所以需要“公钥检索”是因为数据不走加密通道才需要在认证环节单独做 RSA 公钥加密。如果你直接把客户端和服务器之间的连接改成 SSL/TLS 加密通道认证过程就不再需要额外的公钥检索因为整个密码传输过程已经被 TLS 保护了。在 DBeaver 里启用 SSL路径如下右键连接选择“编辑连接”。切换到“SSL”标签页。勾选“使用 SSL”Use SSL。如果服务器没有配置受信任的 CA 证书可以勾选“跳过主机名验证”或“信任服务器证书”具体看你服务器的证书情况。保存后重新测试连接。如果通过 JDBC URL 配置则在连接串里加jdbc:mysql://127.0.0.1:3306/your_database?useSSLtruerequireSSLtrue有些版本还支持 verifyServerCertificatefalse表示不强制校验服务器证书链。4.2 SSL 方案的使用场景和注意事项SSL 方案最大的优势是安全性和兼容性都高。它既不需要关闭驱动侧的安全开关也不用把用户认证插件退回旧版是 MySQL 官方推荐的正向路径。但也有麻烦的地方服务器必须配置好 SSL 证书尤其是自签名证书需要导入客户端信任库否则 DBeaver 会报证书校验失败。实际操作中大多数开发者并不想为了一次本地连库去折腾证书。MySQL 8.0 在初始化数据目录时会自动生成一套自签名 SSL 证书文件通常在 MySQL 的 data 目录下比如 ca.pem、server-cert.pem、server-key.pem。DBeaver 里如果勾选 SSL有时只要把 CA 证书路径指到 ca.pem 就能过证书位置不对时要先查一下SHOW VARIABLES LIKE ssl_ca; SHOW VARIABLES LIKE ssl_cert;MySQL 服务器如果完全没开启 SSL 支持可以在配置文件 my.cnf 里加上[mysqld] ssl-ca/path/to/ca.pem ssl-cert/path/to/server-cert.pem ssl-key/path/to/server-key.pem然后重启 MySQL 服务。我的建议是如果你是图省事那 SSL 不是首选方案一绝对最快。但如果你所在的公司对数据库连接有合规要求或者你需要在公网远程连接数据库那别犹豫直接上 SSL别为了一时方便把密码暴露在不安全的环境里。5. 踩坑实录改完还报错的排查思路5.1 常见的连坐报错有时候按网上的教程改了参数结果还是连不上这时候问题可能不只是公钥检索这么简单了。我把实际排查中遇到过的情况列出来报错一Unable to load authentication plugin caching_sha2_password这种一般是驱动版本太老。老版本的 mysql-connector-java比如 5.1.x不认识 caching_sha2_password 新插件直接就罢工了。解决办法是升级驱动换成 mysql-connector-java 8.0.x 或更高版本。DBeaver 社区版自带驱动通常已经是 8.x但如果你的 DBeaver 比较老或者手动指定过旧驱动就会触发这个问题。报错二Access denied for user rootlocalhost这个才是真正的密码错误或用户权限问题。如果确认密码没错可以检查一下用户的 host 是否匹配比如你的客户端从 192.168.1.100 连过来但 MySQL 里只授权了 rootlocalhost那怎么连都会拒绝。报错三Communications link failure网络层面的问题跟认证无关。检查 IP 写没写对、端口是不是 3306、服务器防火墙有没有放行、MySQL 的 bind-address 是不是只允许本机连接。如果 bind-address127.0.0.1远程是连不进来的。5.2 排查步骤速查表整理了一个排查清单遇到类似问题按顺序过一遍现象排查项解决方向Public Key Retrieval is not allowedDBeaver 驱动属性 allowPublicKeyRetrieval设为 true 或走 SSLPublic Key Retrieval is not allowedJDBC URL 是否手动指定了参数确认参数拼写、大小写正确Unable to load authentication pluginJDBC 驱动版本升级到 mysql-connector-java 8.0Access denied for user用户名、密码、host 是否匹配检查 mysql.user 授权记录Communications link failure网络连通性、端口、防火墙从客户端 telnet 测试端口是否通SSL 证书校验失败CA 证书路径、是否跳过验证确认证书文件路径或临时关闭验证5.3 另外几个容易被忽略的隐藏问题有时候参数改对了但 DBeaver 还是报错原因可能是连接名下面保存了旧连接驱动信息。DBeaver 对每个连接会缓存驱动配置修改“驱动属性”后一定要点“确定”而不是直接点窗口右上角关闭否则修改内容不生效。还有一个常见问题是多个 MySQL 连接共用同一个驱动实例修改一个连接的属性后其他同驱动连接可能也会受影响或者反过来你改了 A 连接的 driver properties但 B 连接加载的还是旧缓存。另外DBeaver 会在连接失败时把错误详情折叠起来默认只显示一句话。如果想看完整堆栈点开错误信息下面的“详细信息”或“查看日志”有时候真实原因和公钥检索无关比如服务器返回的时区信息异常The server time zone value ... is unrecognized也会导致连接中断。这种问题一般需要给 URL 加 serverTimezoneAsia/Shanghai 或改成 useSSLfalseserverTimezoneUTC。还有一种很少被提及的情况同一台机器上装了多个 MySQL 实例一个 5.7 一个 8.0端口分别是 3306 和 3307DBeaver 连接配置里端口写错了连到老实例上行为自然不同。这种问题用最笨的办法排查命令行mysql -h127.0.0.1 -P端口 -uroot -p先连一次看命令行时候能不能过。我在实际工作中最常用的一招是先在命令行用 mysql 客户端连同一个库确认用户名密码和网络都没问题再去排查 DBeaver 侧配置。这样至少能区分是服务器端问题还是客户端问题避免毫无头绪地乱改参数。最后再分享一个小技巧如果你在 DBeaver 里勾完 allowPublicKeyRetrieval 之后仍然报同样的错不妨把 DBeaver 彻底退出再重开一次让它重新加载驱动配置。有些版本对运行中修改的连接属性支持不好重开之后反而好了。我遇到过不止一次这种情况虽然看起来有点笨但实测有效。