资讯动态

DataX连接MySQL 8失败?一份JDBC认证兼容性排查实录

发布时间:2026/10/14 16:55:15 来源:尧图企业网站定制
接到一个不算复杂的同步需求把源库的几张核心表用 DataX 离线抽取到目标库。由于是第一次在这个环境里使用 DataX我从解压安装到写好 json 任务整个过程都按照最简单的来。结果第一次运行就撞了墙——日志先在 reader 阶段报“连接源库失败”紧接着 writer 阶段又报“连接目标库失败”。源库和目标库同时连不上很多人第一反应是网络不通但后来排查了一圈才发现真正原因藏在 JDBC 配置层面而且是一个非常典型、初次接触 DataX 的人特别容易踩的坑。这篇文章把整个排错链路完整记录下来包括我怎么一步步排除网络问题、核对配置、查看驱动版本最终定位到 MySQL 8 默认认证方式与 DataX 内置驱动不兼容的过程。1. 现场记录两个数据库同时失联先从日志找切入点1.1 任务背景与第一条报错当时 DataX 跑在一台独立的执行机上源库地址是10.0.8.101目标库地址是10.0.8.102两个库都是 MySQL用来同步一张订单表。任务文件写好后我用下面这个命令启动python3 bin/datax.py job/sync_order.json大概几秒钟后控制台直接抛出了第一条错误[READER ERROR] DataX无法连接Reader端的数据源 ... Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.还没等我消化完这条信息后面又跟了第二条[WRITER ERROR] DataX无法连接Writer端的数据源 ... Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure看到源库、目标库同时报连接失败我第一反应是执行机到两个数据库之间的网络有问题。但这里有个非常重要的思路两个库同时失败往往不是两台数据库各自出了状况而是某个共性环节出了问题。可能是执行机网络出口被限制可能是配置文件里的连接参数不合法也可能是 DataX 本身使用的驱动与数据库版本不匹配。从 DataX 工作机制来看一条同步任务由 reader 和 writer 各自建立数据库连接任何一个连接失败整个任务都会中止。所以“第一次连不上”的报错顺序并不能说明是源库先坏还是目标库先坏只代表 reader 的连接测试先触发而已。1.2 DataX 连接数据库的基本机制DataX 不是通过一个统一的 JDBC 连接入口去连所有数据库它采用插件化设计。reader.name为mysqlreader时DataX 会在plugin/reader/mysqlreader目录下加载对应的插件 JAR 包插件内部自带一个 MySQL 驱动然后再按照jdbcUrl、username、password这些参数去创建连接。也就是说DataX 最终能否连上数据库取决于三个层面第一执行机到数据库的网络和数据库本身是否可达第二json 配置里的账号密码、库名、连接串参数是否正确第三插件内置的 JDBC 驱动是否能和服务器端的认证协议兼容。这三个层面也对应了下面的排查顺序。当时我犯了一个错误只看了报错里的“Communications link failure”就先去查网络忽略了这条异常在 MySQL 驱动里含义很宽泛既能表示网络不可达也能表示数据库握手阶段失败。真正的具体原因得继续往下看堆栈才能定位。2. 第一轮验证网络、端口、账号全正常问题指向配置层2.1 网络与端口测试既然第一怀疑对象是网络那就从最基础的检查开始。先看执行机能否 ping 通两个数据库ping 10.0.8.101 ping 10.0.8.102结果两个都能正常返回。这说明 IP 层没有断开。接着测试数据库端口MySQL 默认是 3306telnet 10.0.8.101 3306 telnet 10.0.8.102 3306同样都能连上端口不是被防火墙截断的状态。到这里网络连通性基本可以排除。数据库服务本身也应该是在线的否则端口大概率无法建立连接。但这里我想提醒一句ping 通只代表 ICMP 通telnet 端口通只代表 TCP 层能握手成功数据库应用层是否允许这个来源 IP 连接还需要通过实际账号登录来验证。所以下一步测试账号权限。2.2 账号与库权限验证我拿出 json 配置文件里的账号密码直接在执行机上用 mysql 客户端连接mysql -h10.0.8.101 -usync_user -psyncPassw0rd -Dsource_db -e select 1; mysql -h10.0.8.102 -usync_user -psyncPassw0rd -Dtarget_db -e select 1;两个连接都成功了select 1正常返回。也就是说执行机到数据库的网络、端口、账号密码、库级权限都没问题。到这里很多人会困惑既然 mysql 命令行能连为什么 DataX 连不上其实命令行客户端和 DataX 是两套完全不同的客户端实现。mysql 客户端自带它所在版本对应的认证机制而 DataX 插件使用的是另一个独立的 JDBC 驱动。两者能不能连通不能简单互相等价。这个问题我在第二轮的排查里才真正意识到。2.3 初步排查小结把第一轮检查项整理成一张表方便对照检查项方法结果网络连通性ping 两个数据库地址正常MySQL 端口telnet 10.0.8.x 3306正常数据库服务状态mysql 客户端登录正常账号授权使用 json 中的账号密码连接正常JSON 配置文件语法python -m json.tool正常五项检查里有四项基本排除只剩 JSON 配置文件语法这一项也只是初步校验通过。按常规思路接下来应该聚焦在 DataX 自己的配置上包括 jdbcUrl 参数、插件驱动版本、账号密码在 JSON 中的表示方式等。3. 翻配置与驱动JSON 没写错但连接参数和 JAR 版本埋了雷3.1 JSON 配置逐项核对首先我把任务配置文件完整看了一遍重点核对 connection 部分。当时配置类似这样{ job: { content: [ { reader: { name: mysqlreader, parameter: { username: sync_user, password: syncPassw0rd, column: [ id, order_no, amount ], connection: [ { jdbcUrl: [ jdbc:mysql://10.0.8.101:3306/source_db?useSSLfalse ], table: [ orders ] } ] } }, writer: { name: mysqlwriter, parameter: { username: sync_user, password: syncPassw0rd, column: [ id, order_no, amount ], connection: [ { jdbcUrl: [ jdbc:mysql://10.0.8.102:3306/target_db?useSSLfalse ], table: [ orders ] } ] } } } ], setting: { speed: { channel: 2 }, errorLimit: { record: 0 } } } }语法层面先用python -m json.tool验证过没有格式错误。账号密码也没有特殊字符问题不需要转义。但我注意到两个 jdbcUrl 里都只加了useSSLfalse并没有设置时区和字符集。对于 MySQL 8 和老版本驱动组合缺少时区参数会导致驱动解析失败但那是报“无法解析服务器时区”之类而不是“连接失败”。所以当时我也觉得这不是根因只是顺手补充一下而已。3.2 插件内置 JDBC 驱动版本问题的转机出现在检查插件目录的时候。我用 find 命令去翻 DataX 自带的 mysqlreader 和 mysqlwriter 插件find plugin/reader/mysqlreader -name *.jar find plugin/writer/mysqlwriter -name *.jar看到的结果是两个插件自带的都是mysql-connector-java-5.1.x.jar。这个版本本身很常见说明 DataX 初始安装包默认使用的是一个比较老的 MySQL 驱动。而源库、目标库都是 MySQL 8.0。把这种老驱动拿去连 MySQL 8 并不是完全不能连——如果用户认证方式恰好是mysql_native_password5.1.x 驱动往往也能工作。但问题在于 MySQL 8.0 默认的用户认证方式是caching_sha2_password这种认证协议在老驱动里支持得不够完整。这就把怀疑重点引向了认证方式兼容性。3.3 一个容易忽略的字段defaultDriver我在 DataX 的 mysql reader 插件文档里看到实际连接数据库时走的是插件内置的驱动类。虽然我们的 json 没有显式写driverClassName但插件内部会根据名字决定用哪个驱动类老版本还是com.mysql.jdbc.DriverMySQL 8 更推荐com.mysql.cj.jdbc.Driver。不过这里要注意仅改驱动类不一定能解决连接失败因为认证握手阶段的问题更关键。为了确认真正的失败原因我决定把日志级别调高看更底层的堆栈信息。4. 握手阶段失败MySQL 8 默认认证方式与老旧驱动的碰撞4.1 把日志调到 Debug 后发现了关键异常DataX 的日志级别一般由conf/logback.xml控制。为了方便排查我先把root级别的日志从INFO临时调到DEBUG然后重新执行任务python3 bin/datax.py job/sync_order.json这次日志多了一大段内部信息在通信链路异常前面出现了这样一句话Caused by: java.sql.SQLException: Public Key Retrieval is not allowed看到这个异常基本可以锁定了。它并不是网络问题而是JDBC 驱动在连接 MySQL 8 时没有获得服务器的 RSA 公钥无法完成密码传输。MySQL 8 的caching_sha2_password认证默认使用基于 RSA 的密码加密传输。在非 SSL 连接下客户端想验证密码需要先向服务器请求一个 RSA 公钥。JDBC 驱动为了安全默认不允许自动获取公钥必须通过连接参数显式开启allowPublicKeyRetrievaltrue或者使用 SSL 加密连接。源库和目标的 MySQL 版本都是 8.0两个库的用户认证方式都用了caching_sha2_password。DataX 内置的驱动版本又默认禁止公钥检索所以 reader、writer 两边同时握手失败最终表现就是“源库、目标库均连接失败”。4.2 为什么 mysql 命令行能连而 DataX 连不上这是整个排查里最反直觉的一步。客户端能连DataX 不能连原因就在于命令行的连接协议和 JDBC 驱动默认策略不一样。mysql 作为一个完整实现 MySQL 协议的客户端遇到caching_sha2_password时会自动完成公钥请求和密码加密。而旧版 JDBC 驱动为了降低安全风险把allowPublicKeyRetrieval默认设为 false。在没有 SSL 的情况下它不会主动向服务器申请公钥直接拒绝继续握手。所以即使服务器可达、账号正确、密码正确连接也会在最后一个步骤失败。用一个生活化的类比来解释服务器给出一个加密信封新客户端会主动向服务器要钥匙老驱动却默认“我不接受这种钥匙申请流程”于是双方僵持住了。解决办法要么允许客户端向服务器要钥匙要么直接改用加密管道SSL。4.3 连接串里为何没有 allowPublicKeyRetrieval我最初写的 jdbcUrl 是jdbc:mysql://10.0.8.101:3306/source_db?useSSLfalse里面只关闭了 SSL没有开启公钥检索。对 MySQL 5.7 或使用老认证方式的库这样的配置没问题但对 MySQL 8 和默认认证方式正好踩在了驱动和服务器都不兼容的缺口上。另外如果数据库用户使用的是mysql_native_password即使不开allowPublicKeyRetrieval也能正常连。因为老认证协议不需要 RSA 公钥。所以这个问题有一个非常隐蔽的触发条件数据库必须用了 caching_sha2_password且连接没有走 SSL且JDBC驱动版本偏老。三个条件同时满足才爆雷。5. 修复并验证调整连接参数后源库和目标库顺利打通5.1 修改 jdbcUrl 参数找到根因后修复方案就很简单在 jdbcUrl 里显式允许公钥检索同时补上时区参数避免时间类型映射时出现新的麻烦。修改后的连接串jdbc:mysql://10.0.8.101:3306/source_db?useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/ShanghaicharacterEncodingutf8目标库同理jdbc:mysql://10.0.8.102:3306/target_db?useSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/ShanghaicharacterEncodingutf8需要注意的是这些参数是 jdbcUrl 上的查询参数在 JSON 字符串里直接书写即可不需要额外转义。但如果你把连接串放到 XML 或 properties 文件里要注意的转义问题。修改完 json 后我没有急着跑全量任务而是先做了一次只同步 100 条数据的小范围验证控制变量、减少干扰。5.2 重新执行与结果观察再次运行任务python3 bin/datax.py job/sync_order.json这次日志清晰了不少[INFO] reader: mysqlreader [INFO] writer: mysqlwriter [INFO] 任务启动时刻: ... ... [INFO] reader 端连接建立成功开始读取数据 [INFO] writer 端连接建立成功开始写入数据 ... [INFO] 任务结束时刻: ... [INFO] 任务成功总记录数: 100源库和目标库都连接成功了数据也正常写入了目标表。整条链路跑通后我又把日志级别从 DEBUG 调回 INFO重新跑了一次完整表同步确认没有因为日志频繁输出影响性能。5.3 从根上规避这个兼容问题加allowPublicKeyRetrievaltrue是改动最小的办法但它本质上是“允许驱动检索公钥”并不改变数据库的认证方式。如果后续 DBA 换了禁用公钥检索的策略连接依然会受影响。因此还有两种更稳妥的思路第一种把 DataX 插件内置的 MySQL 驱动升级到与 MySQL 8 匹配的新版本例如替换为mysql-connector-j-8.x.jar。但这种操作需要注意插件内部的类和依赖兼容性最好在一个测试环境先行验证。第二种如果 DBA 能配合把 DataX 专用的数据库账号改成使用mysql_native_password认证等于在数据库侧降低协议要求也兼容老驱动。但这不是长久之计未来还要考虑升级驱动和插件。从架构演进的角度我更推荐升级驱动而不是长期依赖allowPublicKeyRetrieval参数。不过在小团队、小任务场景下先加参数快速跑通随后再规划升级是比较实际的做法。6. 复盘DataX 数据库连接失败的通用排查顺序6.1 一套可复用的排错路径这次“两个库同时连不上”的案例能抓出根因靠的是一套递进式排查路径。以后如果再遇到 DataX 连接失败我建议按下面这个顺序走一遍先确认网络可达性ping、telnet IP 3306。网络不通时不要浪费时间去调 json。再用数据库客户端验证账号权限使用 json 里的账号密码直接登录确认账号和库级权限没问题。然后检查 JSON 语法和连接串用python -m json.tool验证格式确认 jdbcUrl 参数完整。接着看 DataX 插件目录里的驱动版本find plugin/reader/mysqlreader -name *.jar对比数据库版本。最后把日志调到 DEBUG定位具体 SQLException 的 Caused by 原因。修复后先小表验证再全量同步。这套顺序的最大价值是不会一开始就陷入“到底是源库问题还是目标库问题”的纠结。两个库同时失败时优先查两者共用的执行环境、共用配置、共用驱动。6.2 几个常见的异常对应表我把这次排查过程中遇到的现象整理成一个快速对照表方便后续定位报错关键字可能原因解决方向Communications link failure网络不通、数据库未启动、握手阶段失败先 ping/telnet再查驱动和认证Access denied for user账号密码错误、host 授权不足检查账号及 grant 权限Public Key Retrieval is not allowedMySQL 8 认证方式与老驱动不兼容加allowPublicKeyRetrievaltrue或升级驱动Unknown database库名写错检查 jdbcUrl 里的数据库名Server returns invalid timezone时区参数缺失加serverTimezoneAsia/Shanghai实际上后面几种异常也是 DataX 入门阶段经常碰到的。多存几张小抄比每次遇到都去搜日志轻松得多。6.3 初次使用 DataX 的三个习惯建议经过这次排错我想给刚开始用 DataX 的朋友三个建议。第一个建议是先做一个最小化任务。不要一上来就配置几十张表的复杂同步而是先选一张小表最好就 100 条数据单独验证 reader 和 writer。这样如果连接出问题不会因为表多、字段多而干扰判断。第二个建议是别拿 mysql 客户端的行为直接推断 DataX。我能连上数据库不代表 DataX 也能连上。JDBC 驱动和命令行客户端是两个完全不同的实现尤其在 MySQL 8 的认证细节上差异很大。第三个建议是养成查看插件 JAR 版本的习惯。DataX 的安装包默认驱动不一定匹配你的数据库版本。动手前先看一眼plugin/reader/mysqlreader、plugin/writer/mysqlwriter目录里到底是什么驱动再决定要不要升级。6.4 关于这次排错的一些个人感受回过头看这次源库、目标库同时连接失败真正的坑不在网络而在“认证协议兼容性”这个隐蔽层面。DataX 本身用起来不复杂甚至可以说 json 配置写好后几乎不用写代码。但恰恰因为它把 JDBC 细节包装起来了用户反而容易忽略驱动版本和数据库版本之间的匹配问题。排查的时候也别怕把日志调到 DEBUG。DataX 的日志结构其实很清楚Caused by后面的那行异常往往直接告诉你答案。像我这次看到 “Public Key Retrieval is not allowed” 的一瞬间所有之前的网络检查基本都可以作废了。以后遇到类似问题我也会更早地把日志级别作为第一步检查项而不是等到网络、账号都验证完才想起来。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑