小易说IT 小易说IT

JDBC + MyBatis 连接 MySQL8.0 两种认证插件配置对比

前提:MySQL 8.0 两大账号认证插件

  • mysql_native_password:兼容老驱动,无 RSA/SSL 强制要求

  • caching_sha2_password:8.0 默认,分SSL 链路、裸 TCP+RSA 公钥两种场景

驱动版本说明:

  • MySQL8 推荐驱动:mysql-connector-java 8.x(包名已改成 com.mysql.cj.jdbc.Driver,不再是com.mysql.jdbc.Driver,旧类名已废弃)

  • Maven 坐标:

<!-- mysql connector 8.x -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.33</version>
</dependency>

一、配置总览对比表

账号认证插件

连接场景

JDBC URL 关键参数

说明

生产推荐度

mysql_native_password

普通内网,无 SSL

jdbc:mysql://ip:3306/db?useSSL=false&serverTimezone=Asia/Shanghai

不需要 RSA,老客户端兼容,5.7 升级迁移常用

⚠️ 安全弱,临时兼容可用

caching_sha2_password

开启 SSL(推荐)

jdbc:mysql://ip:3306/db?useSSL=true&serverTimezone=Asia/Shanghai

SSL 加密链路,直接传输密码,无需 RSA 公钥,最安全

✅ 推荐

caching_sha2_password

不开启 SSL,裸 TCP

jdbc:mysql://ip:3306/db?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true

自动拉取 MySQL 服务端 RSA 公钥加密密码;中间人攻击风险

❌ 仅测试环境

caching_sha2_password

不开启 SSL,指定本地公钥文件

jdbc:mysql://ip:3306/db?useSSL=false&serverTimezone=Asia/Shanghai&serverRsaPublicKeyFile=/data/public_key.pem

本地预置公钥,不从网络拉取,规避中间人风险

✅ 内网无 SSL 场景可选

公共必带参数(8.0 强制,不加会抛时区异常) serverTimezone=Asia/Shanghai characterEncoding=utf8mb4


二、三种完整配置示例(SpringBoot+MyBatis,application.yml)

场景 1:账号使用 mysql_native_password(兼容旧认证)

账号 SQL: ALTER USER 'user'@'%' IDENTIFIED WITH mysql_native_password BY 'Pass@123456';

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test_db?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8mb4
    username: user
    password: Pass@123456
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.xxx.entity

✅ 特点:

  • 驱动不需要处理 RSA;

  • 老项目从 5.7 迁移最简单,不会报认证协议错误; ❌ 缺点:密码哈希算法安全弱,只是临时兼容方案。

场景 2:caching_sha2_password + SSL 加密连接【生产首选】

新建用户默认就是这个插件,MySQL 开启 SSL。

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test_db?useSSL=true&serverTimezone=Asia/Shanghai&characterEncoding=utf8mb4
    username: user
    password: Pass@123456
    driver-class-name: com.mysql.cj.jdbc.Driver

校验 MySQL 是否开启 SSL:登录 MySQL 执行

SHOW VARIABLES LIKE '%ssl%';

✅ 优点:密码在 SSL 加密通道传输,不需要 RSA 公钥相关参数,没有中间人风险。

场景 3:caching_sha2_password,不启用 SSL(内网测试场景)

方案 3.1:自动拉取公钥 allowPublicKeyRetrieval=true(仅测试)

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test_db?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8mb4&allowPublicKeyRetrieval=true
    username: user
    password: Pass@123456
    driver-class-name: com.mysql.cj.jdbc.Driver

⚠️ 风险重点: allowPublicKeyRetrieval=true 允许客户端从网络动态获取 MySQL 服务端 RSA 公钥,中间人可以劫持连接返回伪造公钥,窃取密码,生产严禁开启。

方案 3.2:本地指定 RSA 公钥文件(内网无 SSL,安全备选)

  1. 从 MySQL 服务器导出公钥(MySQL8 默认生成密钥对)

SELECT @@sha256_password_public_key;

复制公钥保存为 public_key.pem,放到应用服务器。 2. JDBC 配置:

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test_db?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8mb4&serverRsaPublicKeyFile=/opt/app/public_key.pem
    username: user
    password: Pass@123456
    driver-class-name: com.mysql.cj.jdbc.Driver

客户端不会从网络拉公钥,使用本地文件,规避中间人劫持风险。


三、MyBatis 本身有没有特殊配置?

MyBatis 不感知 MySQL 认证插件! MyBatis 是基于 JDBC 的持久层框架,认证逻辑全部在 MySQL JDBC 驱动内部完成,MyBatis 只负责 SQL 映射。

只要 JDBC 连接串正确,MyBatis 不需要任何额外修改;连接报错根源全部在驱动和账号认证插件不匹配。

四、常见报错与排查

报错 1:Client does not support authentication protocol requested by server

原因:账号是caching_sha2_password,使用了过低版本 JDBC 驱动(5.x)。 解决:升级驱动到 8.x,或者修改账号为mysql_native_password。

报错 2:Public key retrieval is not allowed

原因:caching_sha2_password,无 SSL 连接,没配置allowPublicKeyRetrieval,也没有指定serverRsaPublicKeyFile。 解决:测试环境加allowPublicKeyRetrieval=true;生产启用 SSL。

报错 3:时区异常 The server time zone value 'CST' is unrecognized or represents more than one time zone

原因:缺少 serverTimezone=Asia/Shanghai,8.x 驱动强制要求。

五、迁移选型建议

  1. 新项目 MySQL8:保持默认caching_sha2_password,开启 SSL 连接,不要用 allowPublicKeyRetrieval

  2. 老系统从 5.7 迁移,短期内不改代码:账号临时改成mysql_native_password,长期逐步迁移到 caching_sha2_password+SSL

  3. 公网访问 MySQL8:必须 SSL,绝对禁止裸 TCP+allowPublicKeyRetrieval

六、原生 JDBC 纯代码示例(便于理解底层)

String url = "jdbc:mysql://127.0.0.1:3306/test_db?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
String user = "user";
String pwd = "Pass@123456";
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection(url, user, pwd);