Navicat 中 MySQL server has gone away 错误怎么办
MySQL 数据库出现 MySQL server has gone away 错误一般是 SQL 语句太大导致了,下面们在使用 Navicat 中操作数据库时提示 MySQL server has gone away 问题解决办法。
今天备份了一下本站的数据,生成的 SQL 文件比较大,当然这个 SQL 是包含了比较多的冗余数据。用 Navicat 直接导入的话,报错 [err] 2006 MySQL server has gone away 。
修改 Navicat 的 max_allowed_packet
打开 Navicat 的菜单中的 tools,选择 server monitor,然后在左列选择数据库,右列则点选 variable 表单项,寻找 max_allowed_packet,将其值改大。
改好之后,再次导入备份的 SQL 文件,一切正常。
其他解决方法
如果还是无法解决,下面我整理了一些 MySQL 查询中碰到 MySQL server has gone away 问题
找到你的 MySQL 目录下的 my.ini 配置文件,加入以下代码:
max_allowed_packet=500M wait_timeout=288000 interactive_timeout = 288000
自己看情况更改数值,我直接改很大,最后记得重启你的 MySQL 服务
这样的话就能很好的解决 MySQL server has gone away 问题了。
- max_allowed_packet 是 MySQL 允许最大的数据包,也就是你发送的请求;
- wait_timeout 是等待的最长时间,这个值大家可以自定义,但如果时间太短的话,超时后就会现了 MySQL server has gone away #2006 错误。
max_allowed_packet 参数的作用是,用来控制其通信缓冲区的最大长度
如果没有修改 MySQL 权限我们可以在 PHP 程序里面,如果 php.ini 修改起来不方便,可以以下代码来尝试解决。
ini_set('mysql.connect_timeout', 300);
ini_set('default_socket_timeout', 300);在 ini_set 后,可以用 ini_get 来验证参数设置适合符合预期。
发布评论
评论列表 6

小熊软糖
我昨天在云服务器上操作的时候遇到了一个非常奇葩的相关问题,我按照文章里的步骤改完了 my.ini 里的所有参数,确认 MySQL 服务也重启成功了,show variables 查 max_allowed_packet 已经是 500M 了,结果用 Navicat 导入大 SQL 的时候还是秒出 MySQL server has gone away 错误,完全想不通哪里出问题。
我折腾了快两个小时才找到原因:我的 SQL 文件是用 Navicat 的「导出 SQL 文件」功能生成的,但是导出的时候我误开了「在每个 INSERT 语句后加 COMMIT」的选项,本来单条 INSERT 语句特别长,几十兆大小,哪怕 max_allowed_packet 已经开到 500M,单条大数据包加上事务提交的网络延迟,直接超过了我设置的 interactive_timeout 等待上限,还没等传输完 MySQL 就主动断开连接了。
后来我没改任何 MySQL 配置,重新导出 SQL 的时候把每条 INSERT 拆成 1000 行一批的批量插入,关闭多余的 COMMIT 语句,再导入的时候全程一点问题都没有。想问下作者有没有碰到过这种配置全改对了还是报错的极端场景,有没有什么排错的思路可以参考?
JSmile
这个情况我之前帮客户排查生产环境问题的时候碰到过一次,当时排查了整整一下午才发现是云服务商的 MySQL 安全组里,偷偷加了 TCP 连接的空闲超时限制,设置成了 30 秒,哪怕 MySQL 自身的 wait_timeout 设成了一整天,30 秒没数据传输云平台就直接把 TCP 连接给断开了,Navicat 这边导入大 SQL 传输慢的时候直接就丢包报错。
碰到你这种所有参数都改对了还报错的情况,给你一套三步排错思路,基本 99% 的场景都能覆盖到:第一步先在 Navicat 的「连接属性 - 高级」里,单独给当前连接设置个「Socket 超时」的数值,改成 300 秒,避免 Navicat 侧主动断连;第二步如果是 Linux 服务器的话,用 tcpdump 抓一下 3306 端口的数据包,看看到底是哪一方发的 RST 断开包,就知道是 MySQL 主动断开、还是中间的防火墙 / 安全组掐了连接;第三步如果还是找不到问题,直接不用 Navicat 走图形化导入,用 MySQL 自带的 source 命令在命令行下导入大 SQL,图形化工具很多时候会有自己的连接超时限制,命令行原生导入的兼容性要稳定得多,基本不会出莫名其妙的断连问题。你说的拆分批量 INSERT 的思路也特别好,不仅能避免触发数据包上限,还能大幅提升大 SQL 的导入速度,比单条插入效率高几十倍。

奶盖加冰
我最近碰到的这个场景好像比文章里说的还要特殊一点,我是在写Python脚本批量往数据库里插入百万条用户日志,跑着跑着脚本就抛2006错误断开连接了,我一开始按照文章里的方法改了my.ini里的三个参数,重启MySQL之后跑脚本还是会出问题。
我查了很久才发现原因:我用的pymysql默认的连接池空闲超时时间,比MySQL设置的wait_timeout还要短,连接在池子里放久了被MySQL主动断开,脚本下次拿连接出来用的时候就会报MySQL server has gone away。我一开始以为改完MySQL的超时参数就万事大吉了,完全没考虑到应用侧的连接保活问题。
后来我在Python的数据库连接配置里加了两个参数才彻底解决,贴一下我最终能用的连接初始化代码:
import pymysql
conn = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='xxx',
database='log_db',
# 开启自动重连
autocommit=True,
ping_interval=60,
# 每次执行操作前先ping一下保活
charset='utf8mb4'
)
不过我之前用文章里给的PHP的ini_set方法的时候,发现居然没生效,查了才知道PHP7已经把原生mysql扩展废弃了,用PDO或者mysqli连接的话直接改php.ini里的mysql.connect_timeout是没用的,能不能请作者补充下不同连接场景下的适配方案呀?
JSmile
你这个场景特别典型,很多人都以为这个报错只有导入大SQL的时候才会出,没想到程序侧长连接空闲也会触发!首先你写的这段pymysql的处理逻辑非常规范,很多开发人员改完MySQL服务端的wait_timeout之后,忘了应用侧的连接池本身也有空闲回收规则,两边的超时时间不匹配的话,必然会出现MySQL已经断开了连接,客户端还以为连接是有效的情况,直接用就抛2006错误。
你提到的PHP新版扩展适配的问题我确实之前文章没写清楚,这里给你补全不同连接驱动的适配代码:如果用的是mysqli的话,不要用老的mysql扩展的ini_set参数,直接在连接后加一行保活判断,示例代码:
$mysqli = new mysqli($host, $user, $pwd, $dbname);
// 连接断开时自动重连
mysqli_options($mysqli, MYSQLI_OPT_RECONNECT, true);
如果是用 PDO 连接的话,可以在初始化 PDO 的时候传入超时参数,同时搭配底层的心跳检测,完全可以避免长连接断开的问题。另外要提醒大家的是,wait_timeout 不要直接盲目设置成几十万秒,最好设置成比你业务侧连接池的最大空闲时间长个 10% 左右,既不会浪费 MySQL 的连接资源,也不会出现连接超时被回收的问题。

失眠选手07
看完这篇文章我差点踩了个大坑!上周我要导入一个差不多 1.2G 的电商历史订单 SQL 备份,一开始按照你说的先在 Navicat 的 server monitor 里改 max_allowed_packet,当时我随手选了 100M,改完点应用之后以为没问题,结果导入到一半还是直接弹出 MySQL server has gone away 的报错。
我一开始还以为是自己操作错了,反复进 Navicat 的变量页看 max_allowed_packet 确实已经变成 100M 了,折腾了快半小时才反应过来,我用的是本地集成环境的 MySQL,Navicat 里改的这个参数是会话级别的临时生效,重启 MySQL 服务之后就会变回默认的 4M!而且我改完 Navicat 的设置之后没重启导入功能的会话,相当于新的参数没对当前连接生效。
后来我按照文章里说的找 my.ini 配置文件改了参数,不过我自己额外加了一步用命令行先确认参数有没有真正生效,跑了下面这条 SQL:
show VARIABLES like '%max_allowed_packet%';
确认查到的值是我设置的1024M之后,重启MySQL再导入就完全没问题了。想问问作者有没有碰到过类似Navicat改参数不生效的情况,有没有什么快速排查的小技巧?
JSmile
你碰到的这个情况特别常见,很多刚接触MySQL配置的用户都会踩这个坑!首先Navicat的server monitor里直接修改的变量,如果你改完没选「Set as permanent value」的勾选框,参数是临时存在当前MySQL连接会话里的,只要断开连接或者重启MySQL就会还原成配置文件里的默认值,我之前第一次操作的时候也踩过一模一样的坑。
给你补充两个快速排查的技巧:第一每次改完max_allowed_packet、timeout这类参数之后,直接在当前查询窗口跑你贴的那行show variables命令,不要信Navicat变量页展示的数值,SQL返回的结果才是当前连接真正生效的配置;第二如果是Windows环境下的集成环境比如phpStudy、小皮面板,很多时候my.ini文件不在MySQL的根目录,而是藏在面板的配置目录里,别找错文件导致改完完全不生效。你后面用的验证方式完全是对的,导入大SQL之前先跑一行select 1测一下连接状态,也能避免导入到一半才发现参数没生效浪费时间。





