MySQL连接数超限典型报错为django.db.utils.OperationalError: (1040, "Too many connections")或日志中反复出现Aborted connection,根源是Django短连接模式下连接未及时释放,导致耗尽max_connections(默认151);关键配置是CONN_MAX_AGE(设0最安全)和wait_timeout匹配,泄漏多发于Celery任务、自定义命令、中间件异常及原生cursor未关闭场景。

MySQL连接数超限的典型报错长什么样
看到 django.db.utils.OperationalError: (1040, "Too many connections") 或 MySQL 日志里反复出现 Aborted connection,基本就是连接池失控了。Django 默认用的是短连接(每次请求新建、用完即关),但高并发下如果连接没及时释放,或中间件/异步任务没正确关闭连接,就会快速耗尽 MySQL 的 max_connections(默认通常 151)。
Django数据库配置里哪些参数最关键
关键不是加连接池库,而是先管住 Django 自身行为。重点调这几个 DATABASES 配置项:
-
CONN_MAX_AGE:设为0表示禁用持久连接(最安全,适合多数场景);设为正整数(如60)表示连接复用秒数,但需确认 MySQL 服务端wait_timeout大于它,否则连接可能被 server 主动断开导致Lost connection -
OPTIONS里加'init_command': 'SET SESSION wait_timeout=28800'可临时延长单个连接超时,但治标不治本 - 不要盲目设
CONN_MAX_AGE> 0 且值过大——比如设成300,又没配好负载均衡的 sticky session,连接会跨请求残留,反而加剧泄漏
哪里最容易漏掉连接没关闭
连接泄漏常藏在非 HTTP 请求路径里:
- 后台任务(Celery)里执行
Model.objects.filter(...)后没触发查询(比如只链式调用没加.list()或.first()),连接不会真正建立,但一旦触发就可能卡住 - 自定义管理命令(
python manage.py xxx)里用了 ORM 却没调connection.close(),尤其循环处理大量数据时 - 中间件中异常未捕获,导致
process_response没执行,连接无法归还给连接池 - 使用原生
connection.cursor()后忘了cursor.close()和connection.close()—— 这比 ORM 更容易出问题
要不要上连接池?用哪个
除非你明确知道瓶颈在连接建立开销(比如单机每秒几百次 DB 请求),否则别急着引入 django-db-geventpool 或 SQLAlchemy + pgbouncer 类方案。Django 官方不推荐第三方连接池,因为:
立即学习“Python免费学习笔记(深入)”;
- 它们绕过 Django 的连接生命周期管理,和
CONN_MAX_AGE、事务控制、多数据库路由等机制容易冲突 - gunicorn + gevent 模式下才有效,但 gevent 本身对 MySQLdb/PyMySQL 兼容性差,常要换
mysqlclient+ 手动打补丁 - 真要用,优先考虑调整 MySQL 侧:增大
max_connections(注意内存占用)、优化慢查询减少连接占用时间、用SHOW PROCESSLIST定期查长期 Sleep 状态连接
连接数问题本质是资源使用节奏和释放时机的问题,不是单纯“加池子”能解决的。最有效的动作永远是:确认每个请求/任务结束前连接是否已关闭,以及有没有不该存在的长连接占着坑。


















