MySQL server has gone away 错误主因是Django连接复用时长(CONN_MAX_AGE)超过MySQL服务端wait_timeout,导致连接被服务端主动断开而Django未检测;应确保CONN_MAX_AGE严格小于wait_timeout(建议设为后者的70%),并配合连接健康检查或close_old_connections调用。
MySQL server has gone away 这类错误在 Django 项目里反复出现,根本不是“偶尔网络不好”,而是连接生命周期没被正确管理。核心问题在于:**Django 默认不主动验证连接有效性,而 MySQL 服务端会按 wait_timeout 主动断开空闲连接**——两者节奏错位,就必然报错。
MySQL 的 wait_timeout 和 interactive_timeout 是什么
这是 mysql 服务端控制连接存活时间的两个参数,默认都是 28800(8 小时),但很多生产环境被设成 300~600 秒(5~10 分钟),尤其云厂商负载均衡后端或容器化部署中很常见。
关键点:wait_timeout 控制非交互式连接(比如 Django ORM、SQLAlchemy),interactive_timeout 控制交互式连接(比如 mysql 命令行)。Django 应用走的是前者。
- 查当前值:
SHOW VARIABLES LIKE 'wait_timeout'; - 别只改 session 级别:
SET SESSION wait_timeout = 7200;无效,必须改 global 或配置文件 - 永久生效要写进
/etc/my.cnf的[mysqld]段:wait_timeout = 7200,然后重启 mysqld
Django 的 CONN_MAX_AGE 和连接池行为
CONN_MAX_AGE 控制 Django 是否复用连接以及复用多久。设为 0(默认)= 每次请求都新建+关闭;设为 60 = 最多复用 60 秒;设为 None = 永久复用(危险)。
问题来了:如果 CONN_MAX_AGE > wait_timeout,连接池里就会存着一堆 MySQL 已经 kill 掉的“僵尸连接”,下次取出来直接报 (2006, "MySQL server has gone away")。
- 安全做法是:
CONN_MAX_AGE必须严格小于wait_timeout,建议留 30% 缓冲,比如 MySQL 设 600 秒,Django 设CONN_MAX_AGE = 420 - 即使设了
CONN_MAX_AGE,Django 也不自动 ping 连接——除非你启用OPTIONS['CONN_HEALTH_CHECKS'] = True(Django 4.2+)或手动加pool_pre_ping=True(SQLAlchemy 场景) - 老版本 Django(close_old_connections() 在每次操作前兜底
为什么 close_old_connections() 不是万能解药
这个函数确实能在执行 ORM 查询前强制关闭所有旧连接,但它治标不治本:
立即学习“Python免费学习笔记(深入)”;
- 它只对 Django ORM 生效,对
connection.cursor()或原生 SQL 无效,得手动调connection.close() - 它不能防止连接池里已失效连接被取出来——只是“用前清一遍”,并发高时仍可能抢在清理前拿到坏连接
- 它增加额外开销,每条 ORM 查询前都触发一次连接状态判断
- 它掩盖了真正的问题:连接复用策略和 MySQL 超时没对齐
PyMySQL / mysqlclient 驱动层的隐性坑
驱动选择直接影响错误表现和修复路径:
-
mysqlclient是 C 扩展,性能好但依赖系统 OpenSSL 和 libmysqlclient 版本,容易因底层库冲突导致连接突然中断(比如corrupted double-linked list错误) -
PyMySQL是纯 Python 实现,无编译依赖,但默认不开启 TCP keepalive,长连接更容易被中间设备(防火墙、ALB)静默断开 - 若用 PyMySQL,务必在 DATABASES 配置里加:
'OPTIONS': {'read_timeout': 30, 'write_timeout': 30, 'charset': 'utf8mb4'},并考虑设'autocommit': True避免事务卡住连接 - 不要混用驱动:Django 设置
'ENGINE': 'django.db.backends.mysql'时,背后实际走的是mysqlclient;想切 PyMySQL,得加pymysql.install_as_MySQLdb(),且注意 Django 版本兼容性(如 4.2+ 对 PyMySQL 支持更稳)
MySQL server has gone away 就会准时回来。


















