最近碰到一个特别典型的达梦数据库问题,现象和标题一模一样:远程客户端工具连接时报6001错误,但在服务器上用disql本机连接一切正常。这个问题问的人非常多,而且很多人第一反应就是数据库坏了、账号密码不对,其实方向完全跑偏了。今天我把这个问题的完整排查思路和解决办法整理出来,包括我自己踩过的坑,希望对做达梦运维和开发的人有所帮助。
1. 先搞清楚“disql能连”到底证明了什么
1.1 本地连接与TCP连接的链路差异
6001错误在达梦数据库里的本质,是客户端在建立通信链路时失败,官方错误描述一般指向“通信环境初始化失败”或“网络通信错误”。也就是说,客户端和服务端之间的TCP会话根本没有建立起来,或者建立起来之后在协议握手阶段被掐断了。
很多人不理解为什么同一个数据库、同一套账号密码,disql能连,工具却连不上。关键就在于:disql在服务器本机执行时,走的不一定是完整的网络链路。
如果你在服务器上直接敲disql SYSDBA/密码不带任何主机和端口参数,达梦默认会使用本地通信方式,可以理解为进程间通信或者回环地址,整个过程不经过外部网卡、不经过防火墙、也不经过网络传输。即便你写的是disql SYSDBA/密码@localhost:5236,走的也基本是回环接口,物理网卡和系统防火墙对这个链路几乎不设防。
而远程客户端工具,比如DBeaver、DataGrip、Navicat或者达梦自带的图形化管理工具,连接逻辑全部走TCP/IP。客户端要路由到服务器IP、服务器端口要处于监听状态、防火墙要放行、监听地址要绑定对外网卡、服务端还要和客户端完成协议版本协商。这一整条链路里任何一环出问题,客户端就给你报6001。
所以记住第一句话:disql能连,只能证明数据库进程活着、账号密码是对的,不能证明远程TCP链路是通的。
1.2 用两条disql命令快速定位问题范围
搞清楚上面的原理之后,第一步要做的事情就非常明确了——在服务器上手动模拟一次“远程”连接,通过对比结果缩小排查范围。
在服务器上用两条命令反复测试:
# 第一条:走回环地址连 disql SYSDBA/你的密码@127.0.0.1:5236 # 第二条:走本机对外IP连 disql SYSDBA/你的密码@192.168.1.100:5236注意,第二个IP要换成服务器实际的对外IP地址,用ip addr或者ipconfig查一下就有。
判断逻辑非常直接:
- 如果两条都能连:说明数据库服务、端口、监听、账号权限都没问题,问题大概率出在你那把远程工具的连接配置或JDBC驱动上。
- 如果127.0.0.1能连,对外IP连不上:说明服务端网络链路有拦截问题,继续往监听地址、防火墙、安全组方向查。
- 如果127.0.0.1也连不上:说明账号密码、实例状态或者端口配置本身就有问题,先不要怪远程工具。
我平时接到类似报障,基本就是用这两条命令把问题一分为二,至少能省掉一半的排查时间。很多人一上来就去看客户端驱动配置,结果折腾半天,最后发现是防火墙没放行,白忙活。
2. 监听地址和端口问题:远程连不上的第一元凶
2.1 用netstat看dmserver到底监听了什么
如果上面两条disql命令出现了“127能连、对外IP不能连”的情况,那优先检查dmserver进程的监听状态。
在服务器上执行:
netstat -tlnp | grep 5236或者习惯用ss命令的:
ss -tlnp | grep dmserver正常情况下应该看到类似这样的输出:
tcp LISTEN 0 128 0.0.0.0:5236 0.0.0.0:* users:(("dmserver",pid=12345,fd=24))重点是看第三列里的监听地址是0.0.0.0:5236还是127.0.0.1:5236。
0.0.0.0:5236表示dmserver监听了本机所有网卡地址,远程只要防火墙放行,理论上就能连。127.0.0.1:5236表示只监听了回环地址,外部IP根本进不来,这时候远程工具报6001就一点不奇怪。
如果是后一种情况,需要去检查达梦实例的dm.ini配置文件里网络监听相关参数,重点看端口配置PORT_NUM和监听地址相关配置。修改之后一定要重启dmserver实例,监听配置属于实例启动时加载的内容,改完不重启是不生效的。
还要注意一种情况:你看到的5236端口根本不是dmserver在监听。服务器上可能存在多个实例,或者这个端口被其他服务占用。用命令的时候把进程信息带出来看一眼,确认pid对应的确实是dmserver进程。
如果没有输出,那就是dmserver压根没起来,或者端口不对。用ps -ef | grep dmserver看一下进程,再确认实例启动时加载的dm.ini文件是哪个。
2.2 端口服务与防火墙放行的核对清单
确认监听地址没问题之后,防火墙就是下一个重点。Linux服务器上最常见的是firewalld和iptables两套体系。
用firewalld的话,先看当前放行端口:
firewall-cmd --list-ports如果列表里没有5236/tcp,执行放行:
firewall-cmd --add-port=5236/tcp --permanent firewall-cmd --reload有的老系统还在用iptables,可以配合检查:
iptables -L -n | grep 5236这里我要单独提醒一句:服务器本机能连、外面连不上,十次里有八次是防火墙问题。而且如果你之前按网上教程直接执行过systemctl stop firewalld这种操作,虽然当时可能放通了,但服务器一重启防火墙又自动起来了,问题反复出现。正规做法是直接把端口加白名单,而不是把防火墙整个关掉。
Windows服务器上,达梦数据库跑在Windows的场景也不少。要去“控制面板-系统和安全-Windows Defender防火墙-高级设置-入站规则”里检查5236端口是否放行,同时确认网络配置文件里当前的网络类型是“专用”还是“公用”,不同的网络配置文件可能套用不同的防火墙规则,经常有人在专用网络里放行了,实际却连着公用网络,掉了坑。
2.3 被忽略的Docker端口映射和云安全组
现在达梦跑在Docker容器里的情况越来越多了,这类部署方式会多个隐藏关卡。
Docker启动达梦实例时,如果端口映射没写好,外部照样连不上。比如启动命令是:
docker run -d -p 5236:5236 \ --name dm8 \ dm:latest这样宿主机所有网卡的5236都会映射到容器。但如果你的启动命令映射写的是:
docker run -d -p 127.0.0.1:5236:5236那宿主机只有回环地址能访问这个容器,外部网络依然进不来。在宿主机上用第一节那两条disql命令测试,表现就是127.0.0.1能连、对外IP连不上。
还有云服务器场景,比如阿里云、腾讯云、华为云。这些平台除了操作系统自己的防火墙,还有一层安全组规则,安全组是流量进入云服务器的前置关卡。你就算在Linux里把firewalld放行得再好,安全组入方向没放行5236/tcp,流量照样进不来。
排查CVM这类环境的时候,一定在控制台里把安全组的入站规则也检查一编才稳妥。安全组和本机防火墙的关系是“先过安全组,再过本机防火墙”,两关都得通。
3. 客户端驱动版本不匹配:最容易漏掉的6001来源
3.1 达梦服务端版本与JDBC驱动的对应关系
如果你的服务器端两条disql命令全部能连通,那恭喜你已经排除了网络层的问题。这时候,6001的最大嫌疑就转移到了客户端工具的驱动版本上。
这里要展开说一个很多新手完全没意识到的点:达梦的JDBC驱动跟服务端版本有极强耦合关系。这个问题太隐蔽了,因为你的工具连接配置、IP、端口、账号密码全是对的,但驱动和服务端的协议版本对不上,连接建立过程中双方握手失败,客户端直接报6001。
比如本机安装了达梦8.1或者某个早期小版本的数据库,结果你从网上下载了一个很新的DmJdbcDriver18.jar,两个版本在协议协商时出现不兼容,就会复现“disql能连、JDBC工具不能连”的诡异现象。反过来也一样,拿老驱动去连新版本数据库,同样可能报6001或类似的其他网络类错误。
所以在排查这个问题时,一定要先确认服务端究竟用的哪个版本。登录达梦数据库后执行:
SELECT * FROM v$version;输出类似:
DM Database Server 64 V8 1-2-156-23.04.20-177039-20015-ENT记录下版本号和编译时间。然后去配置客户端驱动的时候,选择对应的驱动Jar包。最稳妥的办法是直接去达梦安装目录下的dmdbms/drivers/jdbc目录里找对应的DmJdbcDriver18.jar,拷贝到你本机使用。安装目录里的驱动跟当前实例肯定是同一套代码编译出来的,版本不会偏。
这里额外提一句,达梦的JDBC驱动命名中有个“18”,很多初学者以为是JDK18,其实它对应的是JDK1.8。在配置工具驱动的时候,也要注意本机JRE版本和驱动的最低要求匹配。JRE版本太老,加载驱动时会出现各类异常,有时候也会被错误地包装成连接层错误。
3.2 在管理工具和IDE里替换驱动Jar的步骤
接下来说说主流工具里怎么换驱动。
DBeaver是最常被拿来连达梦的客户端之一。操作路径是:“数据库” -> “驱动管理器” -> 找到达梦对应的驱动条目,或者新增一个驱动。在“库”这个Tab页里,把系统默认用的驱动Jar移除,然后添加你从服务器安装目录拷贝过来的DmJdbcDriver18.jar。同时在“URL模板”一栏,确认填的是:
jdbc:dm://{host}:{port}不要照搬某些教程里的jdbc:dm://{host}:{port}/{database}这种格式,达梦的JDBC URL默认不带数据库名,这一点跟MySQL的习惯不一样。如果确实要指定Schema,是在URL后面追加参数,而不是在端口后面加斜杠。
DataGrip里面操作也很类似。“数据源” -> “添加” -> 选达梦(有些版本显示为DM) -> 然后在“驱动”页面底部点“+”,把本地的JDBC Jar添加进来。如果工具版本里根本找不到达梦选项,可以选择Generic JDBC数据源,然后手动填驱动类dm.jdbc.driver.DmDriver和URL模板。
Navicat连接达梦的话,新版Navicat已经内置了达梦支持,但内置驱动的版本不一定适配上你的服务器。如果报6001,就去Navicat的安装目录里看是否有达梦相关驱动文件,或者查一下Navicat官方有没有针对达梦驱动的更新。就我实际使用的经验看,Navicat对达梦的支持力度远不如对MySQL/PostgreSQL那么成熟,连不上时优先考虑换DBeaver去验证。
替换驱动之后,别忘记重启客户端工具。有些IDE缓存了驱动类信息,不重启的话加载的还是旧驱动。
4. 连接串写法与服务配置的隐藏坑
4.1 连接串各项参数逐个说明
网络通了、驱动版本也配对了,仍然报6001的话,就要把注意力放到连接串的写法上。达梦的连接串格式比Oracle简单,但很多用户是从MySQL的习惯带过来的,容易踩坑。
正确的JDBC连接串一般是:
jdbc:dm://192.168.1.100:5236就这么简单,没有数据库名。如果你需要指定Schema,可以按达梦官方文档的说明在URL后面追加参数,但默认情况下不要加任何多余路径。加了不支持的参数,客户端也可能在握手阶段报错。
disql命令形式的连接串,格式是:
disql SYSDBA/密码@192.168.1.100:5236这里有个细节:如果密码里包含特殊字符,比如@、/、#,一定要做转义或者用引号把密码包起来。我见过有人在密码里带了一个@,然后连接串解析错乱,怎么连都报错,还以为是网络问题,折腾半天才发现是密码没处理。
另外,达梦的端口默认是5236,但很多生产环境出于安全会改成其他端口。如果你在工具里填的是默认端口,而服务端实际跑的端口不是5236,那就必然连不上。确认办法直接用第一节的disql命令测试,或者用netstat看dmserver实际监听端口,别想当然。
4.2 dm_svc.conf 服务名配置的注意点
达梦支持通过服务名连接,这种方式在集群或者经常切换IP的环境下特别好用。服务名的配置文件是dm_svc.conf,位置在达梦安装目录的bin目录下或者系统特定路径。
配置内容是类似这样的格式:
DM_SVC_1=192.168.1.100:5236然后客户端连接的时候写:
disql user/pwd@DM_SVC_1JDBC连接串则是:
jdbc:dm://DM_SVC_1这个机制本身没什么问题,但很多人在服务器上测试时用的是IP直连,而工具里填的是服务名,如果服务名对应的地址列表配置有误,或者配置文件里包含了多个实例地址但只有一个是活着的,客户端会逐个尝试,最终全部失败后报出网络相关错误。6001这个错误码就很容易被触发。
有一个容易被忽略的细节是dm_svc.conf里每个实例地址之间用什么分隔符。如果你是从网上复制粘贴的配置,分隔符或者换行方式不对,解析出来的连接列表就是错的,客户端连接自然失败。遇到工具报6001又找不到头绪的时候,建议先在工具里用IP直连方式测试,如果IP直连正常而服务名连不上,那基本可以确定是服务名配置文件的解析问题。
4.3 账号IP限制和连接数上限
还有一个比较隐蔽的场景,是服务端对连接来源做了限制。达梦数据库本身支持对用户来源IP进行访问控制,部分安全版本或者部署在等保环境下的实例,会配置账号只允许特定IP网段登录。如果你的客户端IP不在白名单里,服务端会在认证阶段直接拒绝连接,客户端拿到6001,而你在服务器本机用disql测当然测不出来——因为本地来源IP默认都是在白名单里的。
遇到这种配置,最直观的排查办法是去达梦服务端的日志里找线索。达梦实例日志一般放在安装目录的log目录下,文件名类似dm_实例名_日期.log。打开日志,搜索连接失败的记录,如果能看到“拒绝”“not allowed”之类的关键词,就要往账号访问控制的方向查。
再有一个很容易被忽视的点是连接数达到上限。达梦实例参数里有最大会话连接数的限制,如果当前数据库会话已经满了,新连接也会被拒绝,表现同样是6001或连接超时类错误。通过disql登录后执行:
SELECT COUNT(*) FROM V$SESSIONS;再对比dm.ini里配置的MAX_SESSIONS参数,如果已经非常接近甚至打满,那就不是网络问题,是资源问题。这种情况临时解决办法是杀掉空闲会话,长期解决办法是根据业务实际并发情况调大连接数上限,或者让应用层使用连接池而不是频繁创建新连接。
还需要注意一个热词里提到的现象:达梦未设置会话超时时间。如果客户端工具和服务器之间建立了连接,但长时间空闲,服务端出于安全可能主动断开,客户端的连接池没有感知,继续复用这个死连接,就会在下一次执行SQL时报网络类错误。虽然这个场景多数时候报的不一定是6001,但我在实际项目中确实遇到过空闲回收后重新获取连接报6001的情况。如果只有长时间未操作后才复现6001,优先检查连接池的保活和超时配置,服务端的SESSION_TIMEOUT相关参数也要看一眼。
5. 一套可以照着抄的完整排查流程
5.1 从telnet到disql再到工具的由外到内排查
讲了这么多,最后整理一套完整的排查顺序。遇到“远程工具连6001、disql本机能连”的情况,按照下面这个路径走,基本不会漏问题。
第一步,先做TCP层的连通性验证。在你自己的电脑上用telnet命令测试一下服务器端口的连通性。在Windows上如果提示telnet不是内部命令,需要先到“启用或关闭Windows功能”里勾选Telnet客户端。Linux/macOS执行:
telnet 192.168.1.100 5236如果连接被立即拒绝,或者一直卡住不动,说明TCP层面就不通,直接跳到网络层排查,看防火墙、安全组、Docker端口映射、监听地址这些。如果telnet能通,继续往下走。
第二步,在服务器上执行那两条disql命令做对比:
disql SYSDBA/密码@127.0.0.1:5236 disql SYSDBA/密码@192.168.1.100:5236记录两条命令的执行结果,这一步能把问题精准切成“服务端网络层”还是“客户端驱动层”。
第三步,如果两条disql命令都通,确认服务端版本,然后检查客户端工具的驱动Jar版本。这一步建议大家直接用服务器安装目录里的JDBC驱动拷贝到本机,不要图方便用网上下载的“最新版”。
第四步,检查工具里的连接串。URL、端口、用户名、密码、Schema位置,逐一核对。尤其是从MySQL转过来的,要把那种:3306/dbname的习惯收起来。
第五步,以上全部没问题,去达梦日志里查连接失败记录。这一步能确认服务端到底有没有收到连接请求,以及是哪个环节拒绝的。日志是最客观的,很多时候客户端的报错信息不够具体,服务端日志才是真相出处。
5.2 排错Checklist速查表
我把整套排查浓缩成一张表格,遇到问题照着打勾就行:
| 检查项 | 验证方式 | 异常时的处理 |
|---|---|---|
| dmserver进程状态 | ps -ef | grep dmserver | 启动实例 |
| 端口监听 | netstat -tlnp | grep 5236 | 检查dm.ini端口配置 |
| 监听地址是否为0.0.0.0 | netstat输出 | 检查监听地址配置并重启实例 |
| 本机防火墙 | firewall-cmd --list-ports | 放行5236/tcp |
| 云平台安全组 | 控制台查看入方向规则 | 放行5236/tcp |
| Docker端口映射 | docker ps | 修正映射为0.0.0.0:5236 |
| 服务器本机disql走回环 | disql @127.0.0.1:5236 | 确认账号密码/实例状态 |
| 服务器本机disql走对外IP | disql @对外IP:5236 | 排查监听绑定与防火墙 |
| 服务端版本 | SELECT * FROM v$version | 记录确切版本号 |
| JDBC驱动版本 | 驱动Jar来源与时间 | 改用服务端同版驱动 |
| 连接串格式 | 核对URL和端口 | 修正为标准格式 |
| 会话数上限 | SELECT COUNT(*) FROM V$SESSIONS | 调整MAX_SESSIONS或杀会话 |
| 账号IP白名单 | 服务端日志 | 调整访问控制策略 |
| 客户端连接池空闲回收 | 长时间空闲后复现 | 配置连接池保活/超时 |
这张表我打印过很多次,每次排查达梦连接类的诡异问题都拿出来对照。虽然今天聊的是6001这个具体错误,但其实这个排查路径对达梦其他网络类错误同样适用。
最后说点个人感受。做达梦这类国产数据库的排障,最忌讳的就是经验主义,拿MySQL或者PostgreSQL的思维去套。它的客户端驱动、连接机制、工具生态都自有一套逻辑。6001这个错误说白了就是“客户端和服务端没谈拢”,但没谈拢的具体原因千差万别。多从链路和版本两个维度去拆,比死啃配置文件要高效得多。遇到类似问题的时候,别急着改参数,先把disql那两条对比命令跑了,你就能少走一半弯路。