必须同步配置systemd的limitnofile和mysql的open_files_limit,缺一不可;先用lsof和/proc/pid/limits定位瓶颈,再按80%~90%比例设值并重启验证。

必须同步改 systemd 的 LimitNOFILE 和 MySQL 的 open_files_limit,只动一边基本无效。
先确认是不是真卡在系统限制上
报错不等于真到上限,MySQL 可能自己在疯狂开临时文件却没释放。执行这两条命令快速定位:
-
lsof -p $(pgrep mysqld) | wc -l—— 统计当前打开的 fd 总数 -
cat /proc/$(pgrep mysqld)/limits | grep "Max open files"—— 查内核对该进程实际生效的软硬限制
如果前者(比如 64200)接近后者软限制(比如 65536),说明是系统层瓶颈;如果前者才几百、后者却是 1024,那问题大概率出在 SQL 层:未释放游标、ORDER BY 生成大量磁盘临时表、或 table_open_cache 太小导致频繁开关表文件。
systemd 环境下必须显式配置 LimitNOFILE
现代 Linux(CentOS/RHEL 7+、Ubuntu 16.04+)用 systemd 启动 MySQL 时,/etc/security/limits.conf 默认被忽略——这是最常卡住的地方。
- 编辑服务单元配置:
/etc/systemd/system/mysqld.service.d/limits.conf(目录不存在就创建) - 写入:
[Service] LimitNOFILE=65536
- 执行
sudo systemctl daemon-reload,再sudo systemctl restart mysqld - 验证:
cat /proc/$(pgrep mysqld)/limits | grep "Max open files"输出值应与你设的LimitNOFILE一致
不 daemon-reload、只 restart 不生效;reload 但不 restart 也不生效。
my.cnf 中的 open_files_limit 要留余量且不能带单位
open_files_limit 不是“设多少就用多少”,它是 MySQL 启动时向系统申请的目标值,最终取 min(系统允许最大值, 配置值)。
- 建议设为
LimitNOFILE值的 80%~90%,例如 systemd 设了 65536,my.cnf就写open_files_limit = 55000 - 必须是纯整数,不能写
65536k或65536M - 设得比系统限制高,MySQL 会静默下调,并在 error log 写 warning,不会中断启动
- 重启后进 MySQL 执行
SHOW VARIABLES LIKE 'open_files_limit';,应返回 ≥ 你设的值
Docker、XtraBackup、MySQL 8.0+ 的特殊处理点
这些场景容易漏掉关键环节:
- Docker 运行 MySQL:必须加
--ulimit nofile=65536:65536到docker run命令里,宿主机的ulimit不传递给容器 - XtraBackup 报
InnoDB: Error number 24:它直连 MySQL 文件系统,同样受mysqld进程的 fd 限制约束,不是单独调大xtrabackup自身限制就能解决 - MySQL 8.0+ 若启用了
mysqld_safe包装器,它可能覆盖LimitNOFILE,建议禁用mysqld_safe,直接跑原生mysqld
真正生效的关节点永远是:进程启动那一刻继承的限制值,而不是你后来在 shell 里 ulimit -n 临时改的数字。











