mysql实际可用文件描述符由/etc/security/limits.conf、systemd的limitnofile和open_files_limit三者最小值决定,需用cat /proc/$(pgrep mysqld)/limits、systemctl show mysql、ulimit -n三条命令定位瓶颈,systemd环境下必须修改limitnofile且重启服务才生效。

查清MySQL实际能用多少文件描述符
别光看max_connections设了多少,先确认MySQL进程真正拿到的文件描述符上限是多少。它被三处限制共同掐着脖子:/etc/security/limits.conf、systemd的LimitNOFILE、以及MySQL自身配置里的open_files_limit。三者取最小值,才是MySQL能用的真上限。
执行这三条命令快速定位瓶颈:
-
cat /proc/$(pgrep mysqld)/limits | grep "Max open files"—— 看MySQL进程当前生效的fd上限 -
systemctl show mysql | grep LimitNOFILE(或mariadb)—— 查systemd服务限制 -
ulimit -n(需切换到mysql用户下执行)—— 查该用户shell级限制
如果三者不一致,尤其是systemd显示LimitNOFILE=1024而你改了limits.conf却没生效,那问题就在这里。
systemd环境下必须改LimitNOFILE
CentOS/RHEL 8+、Ubuntu 22.04+等主流发行版默认用systemd管理MySQL,/etc/security/limits.conf对它完全无效。你得直接改systemd服务配置。
操作步骤很明确:
- 创建覆盖配置:
sudo systemctl edit mysql(或mariadb) - 写入:
[Service] LimitNOFILE=65535
保存退出后,sudo systemctl daemon-reload && sudo systemctl restart mysql
重启后立刻验证:systemctl show mysql | grep LimitNOFILE和cat /proc/$(pgrep mysqld)/limits必须都显示65535。否则配置没加载成功。
my.cnf里只配open_files_limit,别碰innodb_open_files
open_files_limit是mysqld启动时向OS申请fd数量的依据,它应该略小于systemd或ulimit设置的值(比如设65535,OS层给65535或65536)。这个值MySQL启动后会尽量满足,但不会超过OS限制。
innodb_open_files是另一回事:它只控制InnoDB能同时打开多少个.ibd表空间文件,跟连接数无关。除非你有上万张独立表且全用innodb_file_per_table,否则保持默认就行,乱调反而可能浪费内存。
my.cnf中只需加这一行:
[mysqld] open_files_limit = 65535
注意:这个值不能大于OS实际给的fd上限,否则MySQL日志里会警告“Cannot allocate memory for the buffer pool”,并且open_files_limit最终仍按OS限制生效。
临时扩容要盯住ulimit -n的90%红线
当已经报Too many connections又没时间改系统配置时,可以用SET GLOBAL max_connections = N临时顶一顶。但N不是随便写的——它必须≤当前ulimit -n值的90%,否则新连接一来,MySQL还是拿不到fd,照样失败。
比如ulimit -n返回1024,那max_connections最多设到920左右。设高了只是幻觉,SHOW STATUS LIKE 'Threads_connected'永远卡在那个数上不动,因为OS根本不放行。
真正容易被忽略的是:哪怕你把max_connections设成10000,只要OS只给了1024个fd,MySQL就只能维持约900个活跃连接。连接池超时、应用重试、DNS解析慢……这些看似无关的问题,在fd吃紧时全会变成压垮连接的最后一根稻草。











