应先查MySQL进程实际打开的文件数(lsof -p $(pgrep mysqld) | wc -l)和内核限制(cat /proc/$(pgrep mysqld)/limits | grep "Max open files"),若远低于上限则排查SQL层问题;必须同步配置systemd的LimitNOFILE和my.cnf中open_files_limit,缺一不可。

这不是MySQL配置错了,是Linux系统给MySQL进程分配的文件描述符上限太低
查清当前MySQL进程实际打开的文件数
别急着改配置,先确认是不是真到了上限。MySQL报Too many open files,但未必是系统限制卡死,也可能是MySQL自己打开了太多文件却没及时释放。
- 用
lsof -p $(pgrep mysqld) | wc -l快速统计当前打开的fd总数 - 用
cat /proc/$(pgrep mysqld)/limits | grep "Max open files"看内核对这个进程的实际限制(注意:它可能和ulimit -n不一致) - 如果统计值接近或等于“Max open files”的soft limit,说明系统层确实触顶;如果远低于该值,但错误日志持续刷屏,就要怀疑临时表、排序缓冲区或未关闭游标在疯狂占坑
为什么只改my.cnf里的open_files_limit没用
open_files_limit只是MySQL的“愿望值”,它会尝试向系统申请更多fd,但最终受制于进程启动时继承的ulimit限制。
- 常见现象:
Could not increase number of max_open_files to more than XXX; set to the original value of XXX,出现在MySQL启动日志里 - systemd服务默认不读
/etc/security/limits.conf,哪怕你给mysql用户配了hard nofile 65535,也大概率被忽略 - MySQL启动时读取的是启动它的shell进程的
ulimit -n值,不是你当前终端的值——所以ulimit -n 65535再执行systemctl restart mysqld完全无效
必须同步调整systemd服务级LimitNOFILE和MySQL内open_files_limit
缺一不可。只调高MySQL参数,它不敢开更多fd;只调高systemd限制,MySQL压根申请不到。
- 编辑
/etc/systemd/system/mysqld.service.d/limits.conf,写入:[Service] LimitNOFILE=65535
- 执行
sudo systemctl daemon-reload && sudo systemctl restart mysqld - 在
/etc/my.cnf中显式设置open_files_limit = 65535(不要留空,也不要设为0) - 重启后进MySQL执行
SHOW VARIABLES LIKE 'open_files_limit';,应返回≥65535
容易被忽略的复杂点:表数量极大或DTS校验触发的隐性爆满
当数据库有7万+张表,又跑DTS全库校验时,MySQL会在单个事务里批量打开所有.frm文件做元数据比对——这时innodb_open_files和open_files_limit即使设到65535也不够用,因为每个表至少占1个fd。
- 监控项
Innodb_open_files超过65535且持续上涨,就是这个信号 - 此时必须把
open_files_limit和systemd的LimitNOFILE一起提到131072甚至更高,并同步调大innodb_open_files - 这类场景下,光看
ulimit -n或SHOW VARIABLES的输出值是误导性的——得盯/proc/<pid>/limits</pid>和lsof实时结果


















