在使用 Spring Boot 开发应用,并连接 MySQL 数据库时,你可能会遇到一个令人头疼的错误:Public Key Retrieval is not allowed
。 这个错误通常出现在你更新了 MySQL JDBC 驱动程序之后,或者在升级了 MySQL 服务器版本之后。 本文将深入分析这个错误的原因,并提供详细的解决方案,帮助你快速解决问题。
错误描述:
当你尝试连接 MySQL 数据库时,可能会在日志中看到以下错误信息:
java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed
这个错误通常伴随着以下异常堆栈:
com.mysql.cj.jdbc.exceptions.SQLError.createSQLException
com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException
com.mysql.cj.jdbc.ConnectionImpl.createNewIO
错误原因:
这个错误的核心原因是 MySQL 服务器拒绝客户端使用公钥检索的方式进行身份验证。 从 MySQL 8.0 版本开始,默认的身份验证插件从 mysql_native_password
更改为 caching_sha2_password
。 caching_sha2_password
插件使用 SHA-256 进行密码哈希,并且默认情况下不允许客户端使用公钥检索的方式进行身份验证,以提高安全性。
解决方案:
以下是一些解决 "Public Key Retrieval is not allowed" 错误的方案,我们将按照推荐程度排序:
-
更新 MySQL JDBC 驱动程序(强烈推荐):
-
这是最安全和最推荐的解决方案。 升级你的 MySQL JDBC 驱动到 8.0 或更高版本。 新版本的驱动程序支持
caching_sha2_password
插件,并且可以正确处理身份验证。 -
在你的 Maven 或 Gradle 依赖项中更新
mysql-connector-java
的版本。 -
确保你的
pom.xml
(Maven) 或build.gradle
(Gradle) 文件中包含正确的依赖:<!-- Maven --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> <!-- 使用最新版本 --> </dependency>
// Gradle implementation 'mysql:mysql-connector-java:8.0.33' // 使用最新版本
-
-
更新 JDBC 连接字符串中的驱动类名:
-
确保你的 JDBC 连接字符串使用了正确的驱动类名
com.mysql.cj.jdbc.Driver
。 -
在 Spring Boot 的
application.properties
或application.yml
文件中,检查spring.datasource.driver-class-name
属性是否正确配置。# application.properties spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# application.yml spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver
-
同时,建议在 JDBC URL 中也明确指定驱动类名,以便更清晰地配置:
jdbc:mysql://127.0.0.1:3306/hmdp?useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true&driverClassName=com.mysql.cj.jdbc.Driver
-
-
更新 MySQL 用户的身份验证插件:
-
如果你的 MySQL 版本是 8.0 或更高版本,并且用户是在旧版本上创建的,升级到 8.0 后需要更新用户的身份验证插件。
-
使用以下 SQL 命令更新用户的身份验证插件:
ALTER USER 'your_user'@'your_host' IDENTIFIED WITH caching_sha2_password BY 'your_password'; FLUSH PRIVILEGES;
替换
your_user
、your_host
和your_password
为你的实际值。
-
-
显式允许公钥检索(不推荐,降低安全性): 本人更新了8.0.33后仍然错误,改为这样才解决
-
作为最后的手段,你可以在 JDBC 连接字符串中显式地允许公钥检索。
-
在你的 JDBC 连接字符串中添加
allowPublicKeyRetrieval=true
:jdbc:mysql://your_host:3306/your_database?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true&driverClassName=com.mysql.cj.jdbc.Driver
-
警告: 这种方法会降低安全性,因为它允许客户端从服务器检索公钥,这可能会受到中间人攻击。 只有在确定没有其他更好的解决方案时才考虑使用。
-
-
检查 MySQL 服务器配置:
- 确保 MySQL 服务器没有强制禁用
caching_sha2_password
插件。 - 检查 MySQL 服务器的配置文件 (my.cnf 或 my.ini),确保没有
default_authentication_plugin=mysql_native_password
这样的配置。 如果有,并且你希望使用caching_sha2_password
插件,请删除或注释掉该配置,并重启 MySQL 服务器。
- 确保 MySQL 服务器没有强制禁用
-
检查 MySQL 用户权限:
-
确保你的 MySQL 用户有足够的权限连接到数据库。
-
你可以使用以下命令检查用户的权限:
SHOW GRANTS FOR 'your_user'@'your_host';
-
确保用户有
CONNECT
权限,以及对数据库的SELECT
、INSERT
、UPDATE
、DELETE
等权限。
-
最佳实践:
- 优先选择更新 JDBC 驱动程序: 这是最安全和推荐的解决方案。
- 在生产环境中启用 SSL 加密: 为了保护数据传输的安全性,强烈建议在生产环境中启用 SSL 加密 (
useSSL=true
)。 - 使用安全的方式管理数据库密码: 避免将密码直接放在配置文件中。 使用环境变量、外部配置管理工具(例如 Spring Cloud Config、HashiCorp Vault)或加密工具来保护密码。
- 定期更新依赖项: 保持你的 JDBC 驱动程序和其他依赖项更新到最新版本,以获得最新的安全修复和功能。
总结:
"Public Key Retrieval is not allowed" 错误通常是由于 MySQL 服务器的身份验证机制与你的 JDBC 驱动程序不兼容造成的。 通过更新 JDBC 驱动程序,更新用户的身份验证插件,或者显式允许公钥检索,你可以解决这个问题。 记住,安全性至关重要,请务必权衡各种解决方案的安全风险,并采取适当的措施来保护你的数据库。