1. 理解"Public Key Retrieval is not allowed"错误

当你使用DBeaver连接MySQL 8.0及以上版本时,可能会遇到这个让人头疼的错误提示。我第一次遇到这个问题时也是一头雾水——明明昨天还能正常连接的数据库,今天突然就罢工了。

这个错误的本质是MySQL客户端与服务器之间的安全握手出了问题。简单来说,当SSL/TLS加密被禁用时(比如你在连接字符串中设置了useSSL=false),MySQL会尝试使用服务器的RSA公钥进行密码交换。但默认情况下,客户端出于安全考虑不会主动请求这个公钥,于是就触发了这个保护机制。

这种情况通常出现在以下几种场景:

  • 新建数据库用户后的首次登录
  • 修改了数据库用户名或密码后重新连接
  • 服务器端执行了FLUSH PRIVILEGES命令刷新权限缓存
  • 从MySQL 5.7升级到8.0后首次连接

2. SSL/TLS配置的深层原理

要彻底解决这个问题,我们需要先了解MySQL 8.0的安全机制变化。MySQL 8.0默认使用了更安全的caching_sha2_password认证插件,取代了之前的mysql_native_password。这个新插件在安全方面做了重要改进:

  1. 密码存储:使用SHA-256算法进行多次哈希,安全性更高
  2. 传输加密:默认要求SSL/TLS加密连接
  3. 密钥交换:支持RSA公钥加密的密码交换

当SSL/TLS被禁用时,认证流程是这样的:

  1. 客户端尝试建立非加密连接
  2. 服务器要求使用RSA公钥加密密码
  3. 客户端需要获取服务器公钥
  4. 如果客户端不允许公钥获取(allowPublicKeyRetrieval=false),连接就会失败

这种设计是为了防止中间人攻击——在未加密的通道上直接传输密码哈希值仍然存在风险。

3. DBeaver中的解决方案

对于DBeaver用户,解决这个问题其实很简单。以下是详细的操作步骤:

3.1 通过驱动属性设置

  1. 在DBeaver中右键点击你的数据库连接,选择"编辑连接"
  2. 在连接设置界面点击"驱动属性"(新版本可能叫"连接属性")
  3. 右键点击属性列表区域,选择"添加新属性"
  4. 添加以下两个属性:
    • allowPublicKeyRetrieval - 设置为true
    • useSSL - 根据你的安全需求设置为truefalse
  5. 保存设置并重新连接
# 驱动属性示例
allowPublicKeyRetrieval=true
useSSL=false

3.2 通过JDBC连接字符串设置

如果你更喜欢直接修改连接字符串,可以这样设置:

jdbc:mysql://localhost:3306/your_database?allowPublicKeyRetrieval=true&useSSL=false

这两种方法效果相同,选择哪种取决于你的使用习惯。我个人的经验是,如果只是临时调试,用驱动属性更方便;如果是生产环境,建议使用连接字符串以便统一管理。

4. 其他场景的解决方案

4.1 命令行客户端(CLI)的解决方法

如果你使用MySQL命令行客户端遇到类似问题,可以尝试以下参数:

mysql -u username -p --get-server-public-key
# 或者指定公钥文件路径
mysql -u username -p --server-public-key-path=/path/to/key.pem

4.2 修改用户认证插件

如果你有管理员权限,可以考虑将用户认证插件改回mysql_native_password:

ALTER USER 'your_user'@'%' IDENTIFIED WITH mysql_native_password BY 'your_password';

不过要注意,这会降低安全性,只建议在测试环境中使用。

4.3 完整启用SSL/TLS

最安全的解决方案是正确配置MySQL的SSL/TLS:

  1. 生成服务器证书和密钥
  2. 配置my.cnf文件启用SSL
  3. 创建具有SSL要求的用户
CREATE USER 'secure_user'@'%' IDENTIFIED BY 'password' REQUIRE SSL;

5. 安全注意事项

虽然设置allowPublicKeyRetrieval=true能快速解决问题,但需要注意安全风险:

  1. 中间人攻击:在未加密连接中获取公钥可能被拦截
  2. 密钥伪造:攻击者可能提供伪造的公钥
  3. 合规要求:某些行业规范可能禁止这种配置

我的建议是:

  • 开发环境可以临时使用allowPublicKeyRetrieval
  • 测试环境应该配置自签名证书
  • 生产环境必须使用正规CA签发的证书

6. 深入排查技巧

如果按照上述方法仍然无法解决问题,可以尝试以下排查步骤:

  1. 检查MySQL服务器日志,通常位于/var/log/mysql/error.log
  2. 在DBeaver中开启详细日志:
    • 帮助 → 错误日志视图
    • 查看连接时的详细错误信息
  3. 使用telnet测试端口连通性:
    telnet your_mysql_host 3306
    
  4. 验证MySQL用户权限:
    SHOW GRANTS FOR 'your_user'@'%';
    

7. 版本兼容性问题

不同版本的MySQL和连接器可能有不同的表现:

  • MySQL 5.7及以下:很少出现此问题,默认使用mysql_native_password
  • MySQL 8.0+:默认使用caching_sha2_password,容易出现此问题
  • Connector/J 8.0+:对SSL和公钥检索有更严格的控制
  • DBeaver 21+:界面选项位置可能有变化,但功能相同

如果你从旧版本升级到MySQL 8.0,建议先测试所有数据库连接工具,确保它们兼容新的认证方式。我在一次升级后就遇到了JDBC应用全部无法连接的尴尬情况,后来是通过批量修改用户认证插件解决的。

8. 最佳实践建议

根据多年处理这类问题的经验,我总结了一些最佳实践:

  1. 开发环境

    • 使用allowPublicKeyRetrieval=true快速解决问题
    • 保持useSSL=false简化配置
  2. 测试环境

    • 配置自签名证书
    • 使用SSL连接但禁用证书验证
    useSSL=true
    verifyServerCertificate=false
    
  3. 生产环境

    • 使用正规CA证书
    • 完全启用SSL验证
    • 禁用公钥检索
    useSSL=true
    requireSSL=true
    verifyServerCertificate=true
    allowPublicKeyRetrieval=false
    
  4. 连接池配置: 如果使用HikariCP等连接池,记得在配置中添加相应参数:

    dataSource.addDataSourceProperty("allowPublicKeyRetrieval", "true");
    dataSource.addDataSourceProperty("useSSL", "false");
    

记住,安全性和便利性往往需要权衡。作为开发者和DBA,我们需要根据具体场景做出合适的选择。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐