免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

MySQL Error 2013排查全攻略:Navicat连接中断的根因与修复

MySQL Error 2013排查全攻略:Navicat连接中断的根因与修复 1. 先把 2013 错误看明白同一个错误码三种完全不同的故事1.1 这个错误码到底在说什么如果你经常用 Navicat 连 MySQL大概率迟早会碰上一行红字Error 2013 - Lost connection to MySQL server during query。我第一次遇到时也懵了明明昨天还连得好好的怎么今天就查询过程中丢失连接了先把这个错误码的官方定义说清楚。MySQL 文档里 2013 对应的是Lost connection to MySQL server during query意思是客户端和服务器之间的连接已经建立但在执行查询的过程中这个连接被中断了。注意它不是连不上服务器——连不上一般报 2003它也不是服务器进程消失了——那个视角的报错是 2006server has gone away。2013 更像是一个复合症状连接本来是活的突然某条链路断了于是客户端在等待结果时发现 socket 已经不可用。问题在于Navicat 弹窗里显示的 2013 错误后面的提示文本往往不完全一样。我整理过几种常见变体Lost connection to MySQL server during query最典型查询中途连接断开一般伴随数据传输中断。Cant connect to MySQL server on xxx (10061)其实已经走到了 TCP 连接阶段但端口拒绝或者握手被重置。Lost connection to MySQL server at reading initial communication packet连接请求发出后在读取服务器的初始握手包时就断了常见于 DNS 反解异常、SSL 握手失败、网络过滤设备丢包。有些场景还会在客户端报 2013服务端错误日志里对应Aborted connection ... Got an error reading communication packets。同样是 2013引发原因可能一个在南一个在北。所以排查的第一步不是急着改参数而是先搞清楚这个连接到底是在哪个阶段断的1.2 三种典型的断法结合我这些年帮同事、帮客户排查的经验2013 基本跑不出下面三种场景场景 A连接一建立就断。你点 Navicat 的测试连接或者刚点开连接立刻弹 2013。这种几乎都在握手阶段客户端发 TCP 请求服务器回握手包中间任何一步出差错都会导致马上断。常见原因包括认证插件不兼容、SSL 配置冲突、bind-address 只监听了本地、防火墙或安全组拦截了后续数据包等。这个场景最好判断因为错误发生时你还没来得及执行任何 SQL。场景 B连接空闲一段时间后执行第一条 SQL 时断。之前连得挺好离开座位喝口水回来再点开表或者执行一条查询啪一下 2013。这种十有八九是空闲连接被回收MySQL 的 wait_timeout 到了、中间 NAT 设备或防火墙把空闲 TCP 连接清了、Navicat 没有发送 keepalive 保活包服务器就当你下线了。连接本身没有坏是它等太久被清理了。场景 C查询/导出大数据量时中断。平时小查询没问题一跑大 SQL、导一张大表、一次性往某张表插入很多数据时就断。这种情况要优先怀疑max_allowed_packet太小或者net_read_timeout/net_write_timeout设置太短导致传输大结果集时超过超时阈值。还有一种隐藏原因服务器自身资源扛不住比如磁盘满、内存耗尽、mysqld 被系统杀掉也会表现为查询中连接丢失。1.3 别把 2013 和它那几个邻居搞混MySQL 连接层的报错很容易混淆我见过不少人把 2003、2006、2013 混为一谈导致排查方向完全跑偏。这里列一个快速区分表错误码含义典型特征2003Cant connect to MySQL server端口不通、服务没启动、网络完全不可达TCP 层就没建立连接1040Too many connections连接数耗尽服务器拒绝新连接2006MySQL server has gone away服务端视角的连接消失常见于服务器重启、连接被 kill2013Lost connection during query客户端视角的查询中连接丢失是我们要讨论的主角顺带说一句2006 和 2013 经常是同一件事的两面服务器进程崩溃或者连接被强制断开时服务端日志里记录的是aborted connection客户端这边根据断的时刻不同可能报 2006 也可能报 2013。所以排查时如果只盯着错误码容易漏掉服务器根本重启过这种大前提。2. 服务端参数掐断连接max_allowed_packet 和超时参数是重灾区2.1 max_allowed_packet最常见的静态元凶先说一个我几乎每次排查 2013 都会先看的参数max_allowed_packet。它的作用是限制 MySQL 能接收或发送的最大数据包尺寸。当客户端发送的单条 SQL 过大或者查询结果集返回的数据包过大时服务器会拒绝继续传输连接就会被直接断开。Navicat 的表现就是跑着跑着突然报 2013尤其是你执行这种操作时查询包含 BLOB、TEXT、JSON 大字段的表一次性插入几千行甚至几万行的 INSERT用 Navicat 的数据传输工具复制大表导出包含大量数据的 SQL 文件再执行。MySQL 8.0 的默认值一般是 64MB5.7 及更早版本默认只有 4MB。如果你的库里有大字段4MB 几乎是一碰就断。查看当前值SHOW VARIABLES LIKE max_allowed_packet;临时调大只对后续新连接生效SET GLOBAL max_allowed_packet 134217728; -- 128MB需要注意的是这条命令对已建立的连接不生效改完以后 Navicat 要断开重连一次。而且SET GLOBAL是运行时修改MySQL 服务重启后会回到配置文件里的值所以要想治本必须写进配置文件[mysqld] max_allowed_packet 128M修改完重启服务systemctl restart mysqld不同系统可能是 mysql 或 mariadb。2.2 wait_timeout 和 interactive_timeout空闲连接被处决第二种高频原因就是连接空闲超时。MySQL 为了不养太多闲置连接会在客户端超过wait_timeout秒没有发任何请求时主动断开。默认值是 28800 秒8 小时看起来很长对吧但很多生产服务器、尤其是云数据库会把 wait_timeout 调到 60 秒、300 秒这类很小的值来节省连接资源。一旦 Navicat 闲着超过这个时间再执行 SQL 就会直接 2013。查看SHOW GLOBAL VARIABLES LIKE wait_timeout; SHOW GLOBAL VARIABLES LIKE interactive_timeout;这里有个容易踩的坑wait_timeout和interactive_timeout是两个独立变量。interactive_timeout针对交互式连接命令行 mysql 客户端默认是交互式wait_timeout针对非交互式连接。Navicat 这类图形客户端大多数情况下走的是非交互式逻辑但不同版本、不同驱动行为不完全一样。所以排查时两个都要看修改时也建议一起改SET GLOBAL wait_timeout 28800; SET GLOBAL interactive_timeout 28800;配置文件里对应[mysqld] wait_timeout 28800 interactive_timeout 28800但我想多说一句不要盲目把 wait_timeout 往大了调。在高并发场景下空闲连接会占用连接数额度你把超时拉到 24 小时连接池里一堆僵尸连接很快就能把max_connections吃光。对 Navicat 这种桌面客户端来说更优雅的解法是让客户端主动保活这个放到后面第 5 章讲。2.3 net_read_timeout、net_write_timeout 和 connect_timeout网络传输超时除了空闲超时还有三个和网络传输相关的超时参数它们在特定场景下也会造成 2013。参数默认值作用典型 2013 场景connect_timeout10s握手阶段服务器等待客户端认证包的秒数网络抖动、DNS 反解慢握手未完成就超时net_read_timeout30s服务器等待从客户端读取数据的秒数客户端长时间不发数据比如上传大 SQLnet_write_timeout60s服务器等待向客户端写入数据的秒数大结果集传输慢客户端处理不过来大查询跑得久、结果集很大时如果net_write_timeout太小服务器可能在数据还没传完时就认定连接超时直接把连接断掉Navicat 就会看到 2013。对远程数据库尤其明显因为跨网络传输本来就慢。查看和修改方式和前面一样SHOW GLOBAL VARIABLES LIKE net_read_timeout; SHOW GLOBAL VARIABLES LIKE net_write_timeout; SET GLOBAL net_read_timeout 300; SET GLOBAL net_write_timeout 300;写配置文件[mysqld] net_read_timeout 300 net_write_timeout 300 connect_timeout 602.4 修改服务端参数的正确姿势最后总结一下服务端参数层面的完整操作流程先用SHOW GLOBAL VARIABLES LIKE xxx确认当前值别凭猜测改。临时验证用SET GLOBAL改完断开 Navicat 再重连。确认有效之后备份原来的 my.cnf再写入新的配置段。重启 MySQL 服务再执行SELECT 1验证一次。配置文件修改示例集中放在[mysqld]下[mysqld] max_allowed_packet 128M wait_timeout 28800 interactive_timeout 28800 net_read_timeout 300 net_write_timeout 300 connect_timeout 60改完以后用命令行验证一下全局变量是否生效避免重启失败或者配置没加载的尴尬。这一步很多人会跳过结果重启完还是老值白折腾半天。3. 认证、SSL 与网络链路握手阶段的隐形杀手3.1 MySQL 8 默认认证插件与老版本 Navicat 的八字不合这个坑在 MySQL 8.0 刚出来那几年坑了无数人直到现在还有人踩。MySQL 8.0 新建用户默认用的认证插件是caching_sha2_password而比较老的 Navicat 版本尤其是 11.x、12 早期版本只认识老牌的mysql_native_password。当时我在一个项目里遇到的现象非常典型MySQL 是 8.0Navicat 是 11.x命令行用 root 登录一切正常但 Navicat 一测试连接就报 2013有时还会带一句Authentication plugin caching_sha2_password cannot be loaded。因为握手阶段客户端和服务端对认证方式谈不拢连接直接被掐断。排查方法很简单在命令行里登录 MySQL 查一下用户对应的插件SELECT user, host, plugin FROM mysql.user;如果你的用户行里 plugin 是caching_sha2_password而 Navicat 又比较老基本就是这个问题。解决办法有两个方向方向一升级 Navicat。这是最推荐的新版本原生支持caching_sha2_password不用动服务器任何配置。方向二把用户认证插件改回mysql_native_passwordALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 你的密码; FLUSH PRIVILEGES;但要注意MySQL 8.4 开始默认禁用甚至移除mysql_native_passwordMySQL 9 更是直接删掉了。如果服务器版本很新这条路会越走越窄。所以遇到兼容性问题优先升级客户端而不是去改服务器的认证插件这才是长期可维护的方案。3.2 SSL 选项惹的祸MySQL 8.0 默认是开启 TLS/SSL 的Navicat 里连接配置默认的 SSL 选项通常是Preferred优先使用 SSL。正常情况下这没问题但如果服务器的 SSL 证书有问题、证书链不完整或者使用自签名证书并且 Navicat 设置成了Verify CA/Verify Full这类严格校验模式连接就会在握手阶段失败报 2013 或者 SSL 相关错误。排查时先看服务器端 SSL 是否正常SHOW VARIABLES LIKE %ssl%; SHOW STATUS LIKE Ssl_cipher;然后在 Navicat 里做一次对照实验编辑连接找到 SSL 选项把它改成Disabled再测试连接。如果改成 Disabled 之后连接恢复正常说明问题就在 SSL 链路上。这里给一个实用建议开发环境不需要传输层加密时直接用 Disabled 最省心生产环境要走 SSL 的话建议用 Navicat 较新版本并在服务器上配置正规 CA 签发的证书或者把自签名证书导入系统信任库别用Verify Full去验一个自己都不信任的证书。3.3 bind-address服务只监听了本机远程当然连不上第三种握手失败的原因是 MySQL 只监听了本地地址。查看服务端监听状态ss -tlnp | grep 3306如果输出是127.0.0.1:3306说明 MySQL 只在本机回环地址上监听远程 Navicat 无论如何都连不进来。这时就算端口测试通也会在连接建立阶段被重置。把 bind-address 改成0.0.0.0才能接受所有 IPv4 连接[mysqld] bind-address 0.0.0.0改完同样要重启服务。顺便检查一下 MySQL 用户表的 host 字段如果用户的 host 是localhost那即使服务监听全网地址远程连进来也会在权限校验阶段被拒。需要创建一个user%或者user具体IP的账号。不过权限拒绝一般报 1045而不是 2013这里就不展开细说了。3.4 防火墙、安全组与 DNS 反解网络层的隐藏关卡网络链路的问题往往最隐蔽因为它不在 MySQL 内部你翻完所有参数也查不到。先做最简单的端口连通性测试。在运行 Navicat 的机器上执行nc -vz 192.168.1.100 3306或者 Windows 下用telnet 192.168.1.100 3306能通说明 TCP 端口可达不通就要往下查Linux 服务器防火墙是否放行了 3306firewall-cmd --list-allfirewalld或iptables -L -n云服务器安全组入方向是否放行 3306 端口是否开启了什么网络策略把 MySQL 的高端口过滤掉。还有一个很多人不知道的坑DNS 反解导致握手变慢、连接超时。MySQL 默认在收到客户端连接时会做一次反向 DNS 解析如果 DNS 服务器响应很慢或者根本没有配置 PTR 记录握手阶段就会卡住最终 Navicat 报 2013错误文本里通常能看到reading initial communication packet。解决办法是在 MySQL 配置里关闭域名反解[mysqld] skip-name-resolve关闭后MySQL 就不会对客户端 IP 做反解而是直接用 IP 匹配用户表的 host 字段。这个参数改完要重启同时要注意原来用userlocalhost这种基于主机名授权的账号在开启skip-name-resolve后可能匹配不上这种情况要把账号 host 改成127.0.0.1或%。3.5 一个顺序化的网络排查清单网络链路问题我习惯按这个顺序查不要跳步nc -vz 目标IP 3306排除端口不通服务器ss -tlnp | grep 3306确认监听地址防火墙规则firewalld / iptables / 云安全组三层都看一遍如果前几步都正常但连接还是握手失败尝试在服务端临时加skip-name-resolve排除 DNS 反解问题最后用命令行客户端复现一次确认网络层结论。4. 服务器资源、连接数与正在跑的大事务2013 背后的稳定性问题4.1 连接数占满新连接被挤掉MySQL 有max_connections上限默认一般是 151实际取决于版本和配置。当连接数被占满时理论上应该报 1040 Too many connections但如果你是在查询过程中连接被断开也要怀疑是否连接数已经逼近极限。查看当前连接数和上限SHOW STATUS LIKE Threads_connected; SHOW VARIABLES LIKE max_connections;Threads_connected接近max_connections时服务器可能已经来不及为新请求分配线程已有的连接也会因为资源争抢而变得极不稳定Navicat 执行一条普通查询都可能超时或者被断开。这时候该做的不是调大连接数而是先排查谁在占用连接。用这条 SQL 看当前连接分布SELECT user, host, db, command, time, state FROM information_schema.processlist ORDER BY time DESC;很多情况下是某个应用连接池配置不合理空闲连接一直不释放把连接数吃满了。调大max_connections是治标让应用侧规整连接池才是治本。4.2 磁盘满、内存不足、mysqld 崩溃连接瞬间全断如果 Navicat 上的连接不是一个一个地断而是所有连接同时断先别查超时参数重点看服务器本身还活着没。uptime看服务器运行时长重启过会很明显df -h看磁盘是否写满MySQL 的 binlog、undo log、临时文件写不进去会触发异常free -m看内存是否耗尽dmesg | grep -i -E oom|mysql看有没有被 OOM Killer 干掉MySQL 错误日志常见路径是/var/log/mysql/error.log或datadir下的*.err文件。我遇到过一次很诡异的情况Navicat 报 2013重连也连不上过一会儿又能连上了。查了一圈才发现是服务器内存不足mysqld 反复被系统杀掉又自动拉起。这种场景光调客户端、调超时都不管用必须从资源层面解决。排查 mysqld 是否重启最简单的是在命令行执行SHOW GLOBAL STATUS LIKE uptime;如果 uptime 很小说明 mysqld 最近重启过。结合错误日志里的启动记录基本就能确认。4.3 长 SQL 导致客户端断开但后端还在跑千万别盲目重试这一条值得单独拿出来说因为处理不当会造成比 2013 本身严重得多的问题。当你执行一条很耗时的 SQL比如几千万行的 UPDATE、大表 JOINNavicat 因为网络超时或者客户端超时先断了报 2013。很多人的第一反应是重新执行一次。但你有没有想过服务器那边可能还在跑这条 SQL。你重试一次等于一个 SQL 跑两遍如果是 UPDATE/INSERT 这类写操作重复执行可能造成数据错乱、主从延迟甚至锁竞争。所以 Navicat 报 2013 之后先别急着重试。打开一个新的命令行或 Navicat 查询窗口检查这条 SQL 还在不在SHOW PROCESSLIST;或者更精细地看SELECT * FROM information_schema.processlist WHERE user ! system user\G SELECT * FROM information_schema.innodb_trx\G如果查询还在执行中你可以决定是等它跑完还是主动终止KILL QUERY 线程ID; -- 只终止正在执行的 SQL连接不断 KILL 线程ID; -- 直接断开该连接KILL 操作要仔细看 ID别把别人的连接给误杀了。这是我实际踩过的坑一次同事误以为 2013 就是查询没跑成功重试了三次结果三条大 SQL 同时在服务器上跑把 InnoDB 的锁竞争直接拉满最后整个库响应都变慢了。5. 一套可复现的排查流程从现象到结论照着做就行5.1 先回答三个问题与其上来就百度错误码不如先回答自己三个问题能筛掉一半以上的可能性什么时候断的连上就断 / 空闲后断 / 查询中途断 / 导出大表时断 / 所有连接同时断。只有 Navicat 断还是命令行也断用mysql -h 127.0.0.1 -P 3306 -u root -p -e SELECT 1复现一次。最近服务器或配置有没有变化重启过 MySQL改过 my.cnf加过防火墙规则云控制台改过安全组磁盘快满了这三个问题回答完方向基本就锁定了。5.2 分场景快速定位表现象优先检查项最可能的根因测试连接即报 2013认证插件、SSL、bind-address、防火墙caching_sha2_password 兼容性 / SSL 失败 / 端口不通空闲一段时间后第一条 SQL 报 2013wait_timeout、Navicat keepalive、NAT 空闲超时空闲连接被服务端或中间链路回收查询大表、导出数据时报 2013max_allowed_packet、net_write_timeout数据包过大 / 传输超时所有连接同时断uptime、错误日志、dmesg、磁盘内存mysqld 重启 / OOM / 磁盘满长 SQL 执行中断且后端仍在跑SHOW PROCESSLIST、innodb_trx客户端超时断开服务器端仍在执行5.3 从命令行开始复现把范围缩小命令行是排查 2013 最好的参照物。很多问题只要用命令行一测立刻就能定位范围mysql -h 127.0.0.1 -P 3306 -u root -p -e SELECT 1如果这条能过说明 MySQL 本身在本地是健康的问题要么在 Navicat 连接配置要么在网络链路非本地连接时尤其要测远程 IP。如果这条也报 2013问题就在服务端或本机网络层。用命令行复现时有一个技巧把报错文本完整记录下来包括括号里 10061、system error 之类的附加信息。这些附加信息比错误码本身更有指向性。5.4 Navicat 侧的调整别忽略了图形界面的隐藏参数不少 2013 问题其实可以通过 Navicat 自身的配置规避。打开连接配置找到高级Advanced或SSH旁边的设置项重点看两个东西Keepalive interval保持连接间隔。这个参数设成 30 或 60 秒Navicat 会定时发送保活包防止空闲连接被 MySQL 的 wait_timeout 或中间 NAT 设备回收。处理空闲一会儿就断的问题时这是最直接的客户端侧解法。SSL 选项。默认通常是 Preferred。如果服务器 SSL 配置有问题改成 Disabled 再试基本能快速排除 SSL 这个变量。还有一个建议Navicat 里把有问题的连接复制一份改一个参数测一次测完再改下一个。这样不会把原始配置弄坏排查过程也有据可查。5.5 验证修改是否生效无论改了服务端参数还是 Navicat 配置都要验证SET GLOBAL改的变量需要 Navicat 断开重连后再确认SHOW VARIABLES配置文件改的要重启服务并确认变量值已经变成新值网络层修改防火墙、安全组用nc -vz重新测试端口大表查询场景用一条会产生大数据量的查询实测比如SELECT COUNT(*)之后再跑一次SELECT * FROM 大表 LIMIT 10000。6. 几个容易被忽略的细节我踩过不止一次6.1 修改超时参数时wait_timeout 和 interactive_timeout 要一起看很多教程只教改wait_timeout但你用 Navicat 连的时候如果驱动走了 interactive 模式真正生效的可能是interactive_timeout。我在一台服务器上遇到过wait_timeout 明明已经是 28800Navicat 还是空闲一分钟就断查了好久才发现interactive_timeout只有 60 秒。服务器上两个参数都改客户端侧再把 keepalive 加上双保险。6.2 别拿开发环境的标准要求生产环境在测试环境把max_allowed_packet调成 1G 很爽但生产环境每个参数都要权衡。数据包上限过大意味着单条 SQL 可以消耗更多内存恶意或误操作时影响面更大。我一般建议生产环境根据实际业务最大单条 SQL 大小来定比如应用有上传 base64 图片的需求就按图片上限算128MB 通常足够没有大字段业务的库64MB 甚至 16MB 也不会有问题。6.3 云数据库要先改参数组别在实例里 SET GLOBAL如果你用的是云数据库 RDS直接执行SET GLOBAL往往会报权限不足即使改了重启后也会被控制台的参数组覆盖。正确的做法是登录云控制台找到数据库的参数组Parameter Group把max_allowed_packet、wait_timeout这些参数在参数组里改完并应用到实例。这个流程比自建库多一步但原理一样云数据库把配置管理收敛到了控制台。6.4 大查询断连后的事后处理比连接本身更重要最后再分享一个处理 2013 时的通用心得先确认服务器端的查询状态再决定要不要重试。我处理这种问题有个固定习惯Navicat 报 2013 后先开一个命令行窗口执行SHOW PROCESSLIST看看刚才那个连接对应的线程还有没有在跑。如果线程已经消失说明服务器端也中断了可以放心重试如果线程还在跑我会先KILL QUERY结束掉残留在服务端的 SQL再做后续操作。这个习惯帮我避免过不少次重复执行导致的数据问题和锁问题。排查 2013 这件事说到底就是先分清楚连接根本没建起来和建起来之后被谁掐了这两大类方向对了基本半天内都能定位到根因。希望这篇文章能让你下次遇到这个错误时不用再靠重启服务器碰运气。
返回列表