2026/10/14 23:35:04

MySQL远程连接报错2013?排查网络和服务端配置全指南

MySQL远程连接报错2013?排查网络和服务端配置全指南 简介针对 Navicat 远程连接 MySQL 时报错 “2013-Lost connection to MySQL server at waiting for initial communication packet” 的问题这份资料整理了一套从服务器端入手的完整排查与修复方案。资源按“检验安装—修改配置—进入 MySQL—授权用户—Navicat 连接”五个阶段组织适合在 Linux 云服务器上部署 MySQL 并需要远程管理的开发者、运维人员阅读。说明文档以单个 PDF 文件提供大小 843KB内容以 CentOS 7 为例覆盖定位 my.cnf、注释 bind-address、配置 skip-name-resolve、通过 vim 修改文件、执行 update user set Host% 与 flush privileges 等授权操作并补充了安全组开放 3306、22 端口及使用 Navicat SSH 通道连接的要点。文档中包含命令示例和界面图示能帮助读者理解问题成因按步骤操作即可减少常见踩坑恢复远程数据库连接。这套排错方案已有 20940 人学习适合作为排查同类初始化阶段断连问题时的参考。1. 2013-Lost connection at waiting for initial communication packet这到底是谁在等谁用 Navicat 远程连 MySQL弹出“2013 - Lost connection to MySQL server at waiting for initial communication packet”大多数人第一反应是去改 Navicat 的等待超时参数改完发现毫无用处。因为这个错误信息并不能理解成“Navicat 等太久了”——TCP 三次握手已经完成问题出在 MySQL 服务端没能在connect_timeout以内把第一个握手包发到客户端或者发包在半路被截走。Navicat 一直在等一个永远不会到达的包卡住直到超时然后给你一条看起来像网络断开的报错。这个错误常见于跨网段远程连接、云服务器、公司内网跳板机后的数据库也出现在 MySQL 刚重启完成但 CPU 被打满的瞬间。它跟密码错误无关、跟数据库版本无关、跟驱动基本无关核心矛盾在网络层和服务端配置。本文按从外到内的顺序拆解网络有没有通、防火墙有没有拦、MySQL 有没有把包发出来、Navicat 侧怎么配合最后给你 5 条我亲手踩过的坑。2. 网络层排查先用三分钟确认这个错误不是防火墙和路由的锅2.1 建连三分钟先看 TCP 通不通再看 MySQL 听没听排查 2013 错误时我的顺序永远先从网络层开始。不要一上来就改 MySQL 配置因为八成问题不在配置。用一条命令判断 TCP 层是否可达# 在 Navicat 所在的机器上执行替换成你的 MySQL 服务器 IP 和端口 nc -vz -w 5 192.168.1.100 3306 # 没有 nc 的环境用 telnet 也一样 telnet 192.168.1.100 3306nc -vz的-w 5表示连接等待 5 秒后失败退出-v输出详细信息。如果输出Connected to 192.168.1.100 port 3306 succeeded说明 TCP 层能通如果卡住直到超时说明路由或防火墙在丢包如果直接Connection refused说明 IP 通但端口没在监听问题定位到 MySQL 进程本身。TCP 通了但 Navicat 还是报 2013就说明三次握手成功了。MySQL 协议里服务端在 TCP 建连后会立刻发送一个握手数据包包含协议版本、服务器版本、连接线程 ID、认证插件和 salt。Navicat 等待的就是这个包。TCP 通、握手包不来通常只有三类原因服务端connect_timeout太短导致它在发包前就判定客户端超时服务端负载过高或 DNS 反查卡住导致握手流程没走完或者包在回程路上被防火墙策略静默丢弃。2.2 用 tcpdump 看握手包到底去哪了网络层判断不能只靠猜抓包是最直接的证据。在 MySQL 服务器上执行# 在 MySQL 服务器上抓取来自 Navicat 客户端 IP 的 3306 端口流量 tcpdump -i eth0 -n -s 0 host 192.168.1.50 and port 3306重点关注四种包客户端发出的SYN、服务端回应的SYN-ACK、连接建立前后的ACK以及任何RST或重复重传。如果看到服务端回了SYN-ACK但客户端没有继续发包问题在客户端到服务端的回程如果SYN进来后什么都没有说明 MySQL 进程没监听到这个包问题在服务端接受队列或iptables的 INPUT 链。有一种非常隐蔽的情况SYN和SYN-ACK都正常服务端也发了应用层数据包但tcpdump里完全看不到任何长度超过 60 字节的包。这通常意味着握手数据包在离开 MySQL 前就被某种机制拦截了比如bind-address只配置了某个网卡地址导致数据从错误的接口发出。抓包能把问题范围缩小到“包根本没产生”还是“包发了但没到”这两者的排查路径截然不同。2.3 iptables 三条规则很多 2013 是被防火墙静默拦掉的DEFAULT DROP策略下只放行了已建立的连接这是最常见也是最坑的配置。假设 MySQL 服务器的iptables规则长这样iptables -A INPUT -p tcp --dport 3306 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT这条规则只允许“已建立连接”的后续包进来而SYN包属于NEW状态会被默认策略丢掉。客户端表现是 TCP 连接根本建立不起来nc会卡住直到超时。但还有一种更隐蔽的写法——NEW状态被放行RELATED状态没放行导致握手包中的某个分片被丢。我习惯直接把 MySQL 端口的规则写成这样iptables -A INPUT -p tcp --dport 3306 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPTNEW允许外部发起新连接ESTABLISHED保证后续通信包畅通。修改后记得测试不要在远程操作时把自己锁在门外。临时测试可以先iptables -I INPUT 1 -p tcp --dport 3306 -j ACCEPT插到第一条验证确认无误后再整理规则。3. MySQL 服务端配置让初始通信包发得出来、发得及时3.1 bind-address 与监听地址远程连不上的头号原因MySQL 的bind-address参数决定了服务端监听哪个网络接口。默认安装的 MySQL 在很多系统上只监听127.0.0.1远程连接时 TCP 请求根本到不了 MySQL 进程。nc测试时端口看起来是通的因为本机回环能连但跨网段连不上或者连上了立刻被拒。查看当前监听情况# 在 MySQL 服务器上执行 netstat -tlnp | grep 3306如果输出是127.0.0.1:3306说明只监听本机回环如果输出0.0.0.0:3306或::3306说明监听所有接口。修改bind-address有两种常见做法改成0.0.0.0监听全部接口或者指定内网网卡 IP。我的建议是能用具体 IP 就用具体 IP少暴露一个面就少一份风险。修改配置文件后重启 MySQL# 编辑 /etc/mysql/mysql.conf.d/mysqld.cnf 或 /etc/my.cnf按实际环境路径 [mysqld] bind-address 0.0.0.0 # 重启 MySQL不同发行版命令不同 systemctl restart mysqld # 或 service mysql restart注意bind-address不要写成逗号分隔的多个 IPMySQL 不支持这种写法。如果服务器有多块网卡但只想监听其中一块直接写那块网卡的 IP。改完用netstat -tlnp再次确认监听地址变化。3.2 connect_timeout 与 back_log第一个握手包不发的两个原因connect_timeout是 MySQL 服务端在 TCP 建连后等待客户端发送第一个数据包的超时时间默认是 10 秒。很多跨网段连接客户端到服务器的 RTT 本来只有几十毫秒但服务端负载高导致进程调度延迟10 秒不够用的情况确实存在。更重要的是 DNS 反查问题——服务端收到 TCP 连接后会尝试反向解析客户端 IP如果 DNS 服务器不可达这个阶段会卡很久connect_timeout就此耗尽。back_log是 MySQL 在拒绝新连接之前允许排队的连接请求数。当短时间内涌入大量连接back_log队列满了之后新的 TCP 连接会被内核直接丢弃客户端侧表现为等待SYN-ACK超时。这两个参数在 MySQL 配置文件中长这样[mysqld] # 默认10秒跨网段或高峰期可调大到15~20 connect_timeout 15 # 默认80连接量大的时候结合内核somaxconn设置 back_log 300调back_log时要同时看内核参数因为 MySQL 的back_log最终受net.core.somaxconn限制。建议对齐# 查看当前内核backlog上限 sysctl net.core.somaxconn # 超过这个值MySQL设置无效需同步调整临时生效 sysctl -w net.core.somaxconn1024还有一个容易被忽略的关联参数wait_timeout和interactive_timeout。前者控制非交互连接空闲多久被服务器关闭默认 8 小时后者控制交互式连接。Navicat 这类图形客户端算交互连接受interactive_timeout控制。如果这个值设置过小Navicat 挂着不动一会儿连接就被服务端回收下次操作时表现出的错误通常是“Lost connection to MySQL server during query”但网络环境恶劣时也会退化成 2013。排查 2013 时顺手看一眼这两个参数没有坏处。3.3 skip-name-resolveDNS 反查导致的“假死等待”这是 2013 错误最容易被误判的场景。现象是Navicat 能连上内网数据库但每次连接要卡 5 到 10 秒有时直接报 2013用 IP 连比用域名连成功率高抓包看到 TCP 开始正常但 MySQL 迟迟不发握手包。原因在于 MySQL 默认会对每个连接做反向 DNS 解析把客户端 IP 解析成主机名。如果客户端 IP 在 DNS 服务器上不存在 PTR 记录或者 DNS 服务器本身响应慢MySQL 的线程会挂在这里等待耗尽connect_timeout后主动断开。解决方法是在配置中加入[mysqld] skip-name-resolve加上之后 MySQL 不再做反向解析连接建立会快得多。代价是SHOW PROCESSLIST里看到的Host列将只显示 IP 而不是主机名掉进user表里的host字段如果写的是主机名也会匹配不上——授权时记得用 IP 或通配符。如果你的user表里有大量基于主机名的授权记录需要先把它们改成 IP 形式否则加了这个参数后所有远程连接都会因为匹配不到账号而被拒绝。3.4 参数清单与重载方式改完不生效的常见原因MySQL 参数表按本场景排查优先级排列参数作用建议值生效方式bind-address监听接口范围0.0.0.0或具体内网 IP重启connect_timeout等待客户端首个包的秒数10~20动态生效back_log连接队列上限根据并发调整重启skip-name-resolve是否做反向 DNS 解析建议开启重启wait_timeout非交互空闲连接关闭时间默认即可动态生效interactive_timeout交互式空闲连接关闭时间7200 左右2小时动态生效动态参数可以不用重启直接验证效果-- 在 MySQL 命令行执行无需重启 SET GLOBAL connect_timeout 20; -- 确认当前值 SHOW VARIABLES LIKE connect_timeout;没有写进配置文件的话重启服务后SET GLOBAL设置会丢所以验证有效后记得落盘到my.cnf。connect_timeout是少数同时支持全局和会话级设置的参数排查时可以直接改全局值不用等连接断开重连。4. Navicat 侧的处理连接选项、SSH 通道与客户端参数4.1 Navicat 连接编辑框里的两个关键设置Navicat 连接设置里有两个和 2013 直接相关的选项一个是「连接超时」或「等待连接超时」另一个是「保持连接间隔」。前者是 Navicat 在建立 TCP 连接时的等待时间后者是空闲时定期发送探测包防止连接被中间设备回收。在 Navicat 的连接属性里把「连接超时」从默认的 10 秒调大到 20~30 秒能缓解部分网络高延迟场景下的 2013。但注意这个参数只控制“建立连接”阶段的等待时间不改 MySQL 服务端的connect_timeout。如果服务端的connect_timeout小于 Navicat 的连接超时实际生效的是服务端那个较小的值调 Navicat 侧无效。「保持连接间隔」建议设置 30 到 60 秒。MySQL 默认wait_timeout是 8 小时但很多云数据库或公司内部中间件会把超时改小——我们环境里遇到过 300 秒甚至 60 秒的配置。Navicat 每隔一段时间发一个轻量查询保持连接活跃就不会触发服务端空闲回收。Windows 下还有一个坑netsh对 TCP 连接的保活设置默认值偏大它控制的是系统层面 TCP keepalive 的探测时间默认 2 小时才发第一个探测包。Navicat 如果依赖系统保活机制空闲连接很容易被中间防火墙先回收# Windows 下把 TCP keepalive 探测时间调为 60 秒需要管理员权限 netsh interface ipv4 set subinterface 以太网 storeactive mtu1500这条命令本身不是改 keepalive 的——实际上 Windows 的 TCP keepalive 参数要通过注册表或Set-NetTCPSetting调整。比较省事的做法是直接用 Navicat 的「保持连接间隔」功能它会在应用层发 ping 包比你调系统内核参数可靠得多。4.2 网络策略挡死 3306 时的备用路径SSH 通道很多线上环境里3306 端口在边界防火墙就被规则拦掉了无论你申请白名单还是改 MySQL 配置都无法直接暴露。Navicat 支持 SSH 隧道把数据库连接封装在 SSH 会话里这是我在某公司遇到跨部门数据库访问时最常用的方案。操作步骤Navicat 新建连接时选择「SSH」标签页勾选“使用 SSH 隧道”填入跳板机地址、端口、用户名和认证方式。数据库连接的主机地址填127.0.0.1端口填3306——因为 SSH 隧道已经把远程 MySQL 端口映射到了本地回环。SSH 通道配置的常见参数 主机跳板机 IP通常为 22 端口 用户名跳板机登录账号 认证密码或私钥文件 数据库主机127.0.0.1隧道已映射 数据库端口3306SSH 通道解决的不只是防火墙问题——它还顺带免掉了 MySQL 侧对公网暴露的顾虑因为 MySQL 可以继续只监听127.0.0.1SSH 服务负责对外。这个方案对网络抖动也有一定缓冲SSH 自带 TCP 保活机制连接不容易被中间设备静默回收。代价是链路多一跳延迟稍高但稳定性通常比裸连 3306 好。用 SSH 隧道后还有一层好处任何iptables对 3306 的封锁策略全都不再影响你因为流量走的是 22 端口。很多公司只放行 22 和 80/443这种环境下 SSH 隧道几乎是唯一干净的解法。4.3 版本兼容性Navicat 连 MySQL 8 时的握手差异MySQL 8 默认认证插件是caching_sha2_password老版本 Navicat通常指 15 以下跟它存在兼容问题。严格说这报的是 1251 错误但很多人在搜索 2013 时会把两者混在一起看。表现特征是连接时能正常建立 TCP 和握手但认证阶段出错或者卡住。如果你是 MySQL 8 环境在 Navicat 老版本上遇到奇怪的连接问题先确认两件事一是 Navicat 版本是否为较新的 16 或以上二是 MySQL 侧账号的认证插件是什么-- 查看账号使用的认证插件 SELECT user, host, plugin FROM mysql.user WHERE user 你的用户名;如果插件是caching_sha2_password但 Navicat 又不支持有两种解决思路把my.cnf里default_authentication_plugin改回mysql_native_password注意 MySQL 8.4 里这个插件可能已被标记废弃需评估再动或者更新 Navicat。我们的经验是优先更新客户端改服务端默认插件会影响所有账号的安全强度属于比较大的变更。5. 避坑2013 错误排查中常见的 5 个坑5.1 改完 MySQL 配置不重启白改半天现象按网上的教程改了my.cnf里的connect_timeout、bind-address用SHOW VARIABLES查询发现值没变连接依然报 2013。原因bind-address和back_log属于启动时读取的参数不重读配置文件就不会生效。很多人只改了文件忘了重启还以为配置没写对。解决修改bind-address这类静态参数后务必备份并重启 MySQL。动态参数用SET GLOBAL生效后会立即作用于新连接但重启后丢失所以两件事都要做——先动态改验证效果再把配置文件改成相同值最后重启。5.2 同时改了 skip-name-resolve 和基于主机名的授权连不上了现象加上skip-name-resolve后原本能连上的账号全部报Access deniedNavicat 换个报错继续让人误以为 2013 没解决。原因MySQL 的user表里授权记录写的是主机名如myuserweb-server开启skip-name-resolve后服务端不再解析主机名连接来源 IP 无法匹配到任何账号。解决开启这个参数之前先确认user表里的host字段都是 IP、网段或%-- 查看是否有基于主机名的授权记录 SELECT user, host FROM mysql.user; -- 如果存在 web-server 这类主机名改成对应的 IP RENAME USER myuserweb-server TO myuser192.168.1.%; FLUSH PRIVILEGES;没有RENAME USER权限的环境先CREATE USER新账号再DROP旧账号。5.3 防火墙 conntrack 表满新连接全被丢现象服务器运行一段时间后突然出现大量 2013重启 MySQL 也没用dmesg里看到nf_conntrack: table full, dropping packetnc测试时 TCP 连接超时。原因Linux 连接跟踪表nf_conntrack默认大小有限当并发连接数或短连接数超过上限新连接的第一个包会被内核直接丢弃客户端侧表现就是连接卡住直到超时与 2013 完全一致。解决# 临时调大连接跟踪表 sysctl -w net.netfilter.nf_conntrack_max131072 # 查看当前使用量与上限 cat /proc/sys/net/netfilter/nf_conntrack_count这种问题通常是业务侧产生大量短连接或连接未正常释放导致的调整容器参数只是治标。长期做法是排查连接泄漏ss -s看timewait和established数量若timewait异常高说明客户端或连接池没有复用连接。5.4 服务器负载过高导致握手包延迟超过 connect_timeout现象MySQL 服务器 CPU 被打满或 IO 等待很高时Navicat 连接要么卡住要么偶发 2013。网络是通的抓包看到SYN和SYN-ACK都正常但 MySQL 应用层握手包迟迟不出来。原因MySQL 收到 TCP 连接后需要在用户态线程里发送握手包。如果 MySQL 线程调度被拖延——比如大量慢查询占满 CPU、磁盘 IO 排队——从网络收到连接事件到发送握手包之间的延迟可能超过connect_timeout服务端主动断开连接。解决调大connect_timeout能缓解症状但根本问题是负载。先看SHOW PROCESSLIST里有什么在跑确认是不是有慢查询在拖累系统。紧急情况下可以把connect_timeout临时调到 30 秒顶住然后排查慢查询——这种场景下别把时间花在调优网络参数上治标不治本。5.5 中间防火墙对空闲连接静默回收现象Navicat 刚连上一切正常挂机几分钟后回来一操作就报 2013重新连接又能用。看起来像随机问题但频率和设备空闲时长强相关。原因网络路径上的防火墙或负载均衡设备出于资源管理考虑会对长时间空闲的 TCP 连接发送RST或直接删除连接状态且不通知两端。MySQL 服务端和 Navicat 都不知道连接已经失效下次发送查询时发现连接已死。解决在 Navicat 里设置「保持连接间隔」为 30 秒让空闲连接持续有数据流动。同时检查 MySQL 侧有没有比wait_timeout更小的中间层回收规则——某些云数据库或自建的连接代理产品会在 60 秒到 5 分钟之间回收空闲连接这个值你直接在 MySQL 上是看不见的只能靠测试确认。6. 进阶验证把 2013 从“玄学”变成可复现的排查流程6.1 一次 tcpdump 抓包完整还原整个握手过程2013 错误最令人头疼的地方在于它的偶发性。同样的 Navicat、同样的网络有时候能连上有时候报错。固定复现路径是排查的第一步打开 tcpdump保存完整数据对比正常连接和失败连接在握手阶段的差异。# 分别抓两次连接保存为文件再比对 tcpdump -i eth0 -n -s 0 -w /tmp/mysql_success.pcap host 192.168.1.50 and port 3306 # 失败后按 CtrlC 停止再抓一次失败场景 tcpdump -i eth0 -n -s 0 -w /tmp/mysql_fail.pcap host 192.168.1.50 and port 3306用 Wireshark 打开两个 pcap 文件直接看 MySQL 协议层的 Server Greeting 包成功场景里 TCP 三次握手完成后对端会立刻发来一个包含版本号的握手包失败场景里你只看到三次握手完成的ACK然后什么都没有直到客户端发出FIN或RST。这一行为就能定位问题在“服务端没发包”而不是“包被网络丢了”——前者查 MySQL 进程后者查防火墙和链路。如果两次抓包都有 Server Greeting 包但 Navicat 还是报 2013那就看 tcpdump 的时间戳Greeting 包和客户端下一个包之间如果隔着很大的间隔可能是客户端的 TLS 握手或认证插件协商阶段超时了。MySQL 8 默认开启 TLS 支持时握手包之后客户端要启动 TLS 协商这一阶段同样可能被防火墙策略干扰。6.2 用 MySQL 错误日志确认连接线程的死亡原因抓包只能告诉你“包没到”不告诉你“MySQL 为什么不发”。把 MySQL 的错误日志打开临时提高日志级别能看到更接近根因的线索[mysqld] # 记录所有连接相关的断开和异常信息 log_error_verbosity 3# 日志位置各发行版不同通常在 /var/log/mysql/error.log tail -f /var/log/mysql/error.log错误日志里如果出现Aborted connection ... Got an error reading communication packets说明 MySQL 服务端在等待客户端数据时遇到了异常。Aborted connection的计数太高基本可以确定是网络层在丢弃数据包而不是服务端本身的问题。配合SHOW GLOBAL STATUS LIKE Aborted%;可以对比正常时段和故障时段的差异。我自己的排查习惯是每次都把 tcpdump 结果、MySQL 错误日志和SHOW GLOBAL STATUS三个数据源的输出放在一起比对。2013 这种问题单看任何一个都容易被误导——比如错误日志里全是Aborted connection看起来像客户端断连但 tcpdump 会告诉你这些连接在握手阶段就被服务端掐断了根因又绕回connect_timeout或 DNS 反查。三份数据一交叉问题范围立刻缩小一半以上。这个流程跑过一次之后2013 就不再是玄学了。现在每次我遇到同类问题第一反应永远是抓包看时间线而不是先去改参数——因为多数情况下参数只是背锅的。希望这套排查路径对你有用下次再碰到至少知道从哪下手了。本文还有配套的精品资源点击获取