MySQL强制SSL需三者同步:用户创建时显式指定REQUIRE SSL、全局设require_secure_transport=ON拦截非加密连接、客户端驱动(如JDBC)明确启用SSL握手,缺一不可。

MySQL 8.0+ 创建用户时直接要求 SSL
MySQL 不是靠“开启某个全局开关”来强制 SSL,而是通过 REQUIRE SSL 在创建或修改用户时声明。没加这句,哪怕服务端配置了 require_secure_transport=ON,老用户也可能绕过。
实操建议:
- 新建用户必须显式写
CREATE USER 'u'@'%' REQUIRE SSL;,不能事后用ALTER USER补(MySQL 8.0.22+ 才支持对已有用户补REQUIRE SSL) - 如果用户已存在且没加
REQUIRE SSL,先确认 MySQL 版本 ≥ 8.0.22,再执行ALTER USER 'u'@'%' REQUIRE SSL; -
REQUIRE SSL和REQUIRE X509不等价:前者只验连接是否加密,后者还强制校验客户端证书——多数业务只需前者
验证用户是否真被强制 SSL
光看 SHOW CREATE USER 'u'@'%'; 输出有 REQUIRE SSL 不够,得实际测连通性。常见错误现象是应用连不上,报错 SSL connection error: protocol version mismatch 或静默断连。
实操建议:
- 用命令行模拟非 SSL 连接:
mysql -u u -p -h your-host --ssl-mode=DISABLED,应失败并提示Access denied for user(不是证书错) - 成功连接后查
SELECT ssl_type FROM mysql.user WHERE User='u' AND Host='%';,值应为ANY(对应REQUIRE SSL) - 连接成功时,
STATUS或SELECT * FROM performance_schema.status_by_thread WHERE variable_name='Ssl_cipher';应显示非空 cipher 名
require\_secure\_transport=ON 的真实作用范围
这个全局变量不是“让所有用户走 SSL”,而是“拒绝任何未加密的连接请求”。但它不改变用户权限逻辑,只在连接建立初期拦截。容易踩的坑是以为开了它就一劳永逸,结果发现 root 用户仍能免密、免 SSL 登录本地 socket。
实操建议:
- 该参数只影响 TCP 连接,Unix socket 连接(如
localhost)默认绕过,不受限 - 若需彻底禁用非 SSL 连接,必须同时确保:1)
require_secure_transport=ON;2)所有用户都带REQUIRE SSL;3)应用连接不走localhost(改用127.0.0.1强制走 TCP) - 修改后需
FLUSH PRIVILEGES;,否则部分旧连接可能缓存旧权限状态
Java/JDBC 连接时 SSL 参数必须显式配全
即使 MySQL 端设了 REQUIRE SSL,JDBC 默认不启用 SSL,会直接报 Access denied。这不是权限问题,是驱动根本没发加密握手。
实操建议:
- URL 必须带
?useSSL=true&requireSSL=true(MySQL Connector/J 8.0+ 推荐用&sslMode=REQUIRED) - 如果服务端没配证书(仅用加密不验证书),要加
&sslMode=REQUIRED&allowPublicKeyRetrieval=true,否则报Public Key Retrieval is not allowed - Spring Boot 配置里,
spring.datasource.url中的 SSL 参数不能丢,spring.datasource.hikari.connection-init-sql等机制救不了连接层失败
MySQL 强制 SSL 的关键不在“开一个开关”,而在于三处同步生效:用户定义带 REQUIRE SSL、全局 require_secure_transport 拦非加密通道、客户端驱动明确启用 SSL 握手。漏掉任意一环,都会出现“以为强制了,其实没生效”的情况。










