ORA-28040只发生在低版本客户端连接高版本服务器(如11g客户端连19c服务器),19c客户端连11g服务器不会触发该错误;因11g服务器无SQLNET.ALLOWED_LOGON_VERSION_SERVER参数,不校验协议匹配性,仅检查密码哈希格式、账户状态等基础项。

Oracle 19c 客户端连接 11g 服务器报 ORA-28040,根本不是“版本太高连不上老库”,而是方向反了——ORA-28040 只发生在“低版本客户端 → 高版本服务器”场景,19c 客户端连 11g 服务器时绝不会触发这个错误。你看到的报错,大概率是搞错了客户端/服务器角色,或日志抄错了。
确认谁是客户端、谁是服务器
很多人凭直觉认为“19c 是新东西,肯定更强势”,但 Oracle 的认证协议控制逻辑是单向的:SQLNET.ALLOWED_LOGON_VERSION_SERVER 管的是“谁可以连进来”,SQLNET.ALLOWED_LOGON_VERSION_CLIENT 管的是“我能连出去找谁”。19c 客户端本身不读 sqlnet.ora(除非用 OCI 模式且显式配置了本地 sqlnet.ora),它只按自己驱动内建规则发起协商。
- 如果你用的是 JDBC Thin(绝大多数 Java 应用、Kettle、DBeaver 默认模式),那 19c 客户端根本不受服务端
sqlnet.ora影响,也不会因协议问题被 11g 服务器拒绝 - 如果你用的是 SQL*Plus 或 PL/SQL Developer 的 OCI 模式,并且该工具指向了 19c 的
instantclient,那它作为客户端,会尝试用 19c 支持的高协议版本去连 11g 服务器——此时真正该报的错是ORA-28040的反向变体,但 Oracle 11g 根本不校验这个参数,通常直接报ORA-12514或静默断连 - 真实出现
ORA-28040的日志堆栈里,T4CTTIoauthenticate.receiveOsesskey这类调用一定出现在客户端堆栈中,且上层是oracle.jdbc.driver.包 —— 这说明是 JDBC 客户端在跟服务器握手失败,服务器必然是 19c 或更高
为什么 11g 服务器不可能抛出 ORA-28040
Oracle 11g 没有 SQLNET.ALLOWED_LOGON_VERSION_SERVER 这个参数,它的认证协议控制逻辑是宽松的:只要密码哈希格式能识别(比如 10G、11G),就放行。它既不会主动拒绝“太新”的客户端,也没有能力判断对方协议是否“匹配”。
- 11g 服务器收到 19c 客户端的登录请求时,只检查用户名密码是否正确、账户是否解锁、资源限制是否超限,不会校验“你用的是不是 TLSv1.2”或“你的认证密钥交换是不是 SHA-256”
- 如果真连不上,常见原因是:监听器没起来、服务名写错、防火墙拦截、用户被锁、密码过期,或者 JDBC URL 里用了 19c 才支持的语法(如
oracle.net.authentication_services=(KERBEROS5)) -
ORA-28040在 Oracle 官方文档中明确定义为 “The authentication protocol requested by the client is not supported by the server”,即“客户端要求的协议,服务器不支持”——11g 服务器不支持的协议,19c 客户端根本不会主动提
排查建议:先看日志源头和堆栈
别急着改配置,先确认错误到底从哪来:
- 打开客户端日志(JDBC 加
?oracle.jdbc.Trace=true,SQL*Plus 开set echo on+sqlnet.ora开 trace),看第一行报错是不是真的ORA-28040 - 检查堆栈最顶端类名:如果是
oracle.jdbc.driver.开头,说明是 JDBC 客户端在报错,服务器一定是高版本;如果是oracle.net.或tnslsnr相关,才可能是监听器侧问题 - 用
tnsping测试网络层通不通,再用sqlplus /@tns_alias测试基础连接,排除 TNS 配置问题 - 执行
SELECT * FROM v$version;在目标数据库里确认实际版本——有时候 DBA 告诉你是 11g,结果其实是 19c 的 PDB,或用了 11g 的客户端连了 19c 的 CDB
真正容易被忽略的是:报错截图或日志复制时漏掉了关键前缀,比如把另一台机器上刚发生的 19c 服务器报错,误认为是当前 11g 连接的错误。协议协商失败这事,永远发生在“说话更强势”的那一端——而 11g 服务器,在认证这件事上,从来就不强势。











