Java 连 SQL Server 报 TLS10 is not accepted?先查 JDK 默认禁用了啥
现象:驱动 SSL 握手失败,提示服务器选了 TLS1.0,客户端只接受 TLS1.2/1.3。
结论:高版本 JDK 默认禁用 TLSv1/TLSv1.1;在无法升级库端 TLS 时,可临时放开jdk.tls.disabledAlgorithms,长期仍应升到 TLS1.2+。
1. 现象
用 Microsoft JDBC 连接 SQL Server 时,控制台出现类似:
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException:
驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。
错误:“The server selected protocol version TLS10 is not accepted by client preferences [TLS13, TLS12]”
Caused by: javax.net.ssl.SSLHandshakeException:
The server selected protocol version TLS10 is not accepted by client preferences [TLS13, TLS12]
人话版:客户端只愿意用 TLS1.2/1.3,服务端却只给出 TLS1.0,握手谈不拢。
2. 环境
| 项 | 典型值(按你的现场改) |
|---|---|
| JDK | 8u291+ / 11 / 17(越新越容易踩) |
| 驱动 | mssql-jdbc |
| 数据库 | SQL Server(仅启用 TLS1.0,或未开 TLS1.2) |
| 部署 | 本地 / 测试 / 生产(勿写内网细节) |
分水岭:Oracle JDK 8u291 起默认禁用 TLS1.0/1.1;后续 11、17 同样默认禁用。
3. 排查路径
按这个顺序查,避免一上来乱改配置:
- 确认报错关键字 → 有
TLS10 is not accepted by client preferences [TLS13, TLS12],基本可断定是协议版本协商失败,不是账号密码错。 - 确认本机/容器实际 JDK →
java -version,看是不是 8u291+ 或更高大版本(容器里经常「以为是 8,实际是 17」)。 - 确认库端 TLS 能力 → 运维侧看 SQL Server 是否只开了 TLS1.0;能开 TLS1.2 就优先开,后面步骤可省略。
- 确认改的是正在跑的那份 JDK → 机器上多 JDK 时,改错目录等于没改;以进程的
JAVA_HOME/ 启动脚本为准。 - 仍失败再查外围 → 防火墙、反向代理、负载均衡是否做了 TLS 终结或拦截。
4. 根因
一句话:库端还在 TLS1.0,客户端 JDK 默认已经把 TLS1.0/1.1 拉黑了。
- SQL Server 端:仅启用 TLS1.0(或业务库长期未升级加密协议)。
- Java 端:从 JDK 8u291 起,安全策略默认禁用
TLSv1、TLSv1.1。 - 握手时服务端选出 TLS1.0,客户端拒绝 →
SSLHandshakeException。
这不是 JDBC「突然坏了」,而是 JDK 安全基线抬高 后与旧库不兼容。
5. 解法
优先方案(推荐):升级 SQL Server 侧 TLS 到 1.2+
从安全与合规看,这是正解。客户端改安全文件只是权宜之计。
临时方案:放开 JDK 对 TLS1.0/1.1 的禁用
步骤 1:定位 java.security(改前先备份)
| JDK | 常见路径 |
|---|---|
| JDK 8 | $JAVA_HOME/jre/lib/security/java.security |
| JDK 11+ | $JAVA_HOME/conf/security/java.security |
示例(JDK 8):
/path/to/jdk1.8/jre/lib/security/java.security
步骤 2:改 jdk.tls.disabledAlgorithms
找到类似配置:
# before(示例,以你文件实际内容为准)
jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, \
DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, ...
本问题的最小必要改动是去掉对 TLS1.0/1.1 的禁用,例如:
# after:去掉 TLSv1、TLSv1.1(其余项按你们安全基线保留)
jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, \
DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL, ...
说明:
- 真正卡住握手的通常是
TLSv1/TLSv1.1。 - 是否同时去掉
3DES_EDE_CBC取决于服务端 cipher;不要无脑整行删光,只删协商失败相关的项,并保留团队安全要求的其他算法禁用。 - 不同 JDK 小版本该行内容不一致,以本地文件为准做 Diff,不要整行复制网上示例覆盖。
步骤 3:重启使用该 JDK 的 Java 进程
只改文件不重启不会生效。改完再连库验证。
不推荐但常见的「假解决」
- 连接串里关加密(如盲目
encrypt=false):可能绕过现象,但把明文风险带进环境,生产慎用,且新版本驱动默认行为也在变。 - 只改了本机 JDK、容器/CI 仍是另一份 JDK:表现为「我电脑好了,流水线还挂」。
6. 防再发
- 新环境连旧 SQL Server:先确认库端 TLS ≥ 1.2,再谈应用配置
- 多 JDK / 容器镜像:改配置前确认进程真实
JAVA_HOME -
java.security变更走变更单 + 备份 + 回滚说明 - 临时放开 TLS1.0 要记技术债,限期推动库端升级
- 把本机验证通过的 JDK 路径写进 README / 部署文档,避免同事改错目录
#祖传代码排障 #Java #SQLServer #TLS #SSL #JDK
关于我
「Java祖传代码守护者」——记录真实 Java 开发踩坑,并把解法沉淀成可复用的知识。
若本文帮到你,欢迎点赞、收藏;有同类坑欢迎评论区补充场景。