MySQL open_files_limit不生效的主因是系统级限制未同步:需依次配置systemd的LimitNOFILE、/etc/security/limits.conf(若非systemd环境)、my.cnf中[mysqld]段纯数字值,三者缺一不可。

open_files_limit 设置不生效的常见原因
MySQL 启动时会尝试设置 open_files_limit,但实际生效值往往低于你配置的数字——这不是 bug,是系统级限制在“卡脖子”。MySQL 无法突破操作系统对进程能打开文件数的硬限制(ulimit -Hn),也不会自动提升它。
- Linux 系统默认
ulimit -n通常是 1024,哪怕你在my.cnf里写了open_files_limit = 65535,MySQL 启动后查SHOW VARIABLES LIKE 'open_files_limit';得到的大概率还是 1024 或略高(比如 5000,取决于 MySQL 自己的估算逻辑) - systemd 服务(现代主流发行版默认)会忽略
/etc/security/limits.conf对服务进程的设置,必须单独配LimitNOFILE -
open_files_limit在配置文件中写成 0 表示“让 MySQL 自己猜”,这通常导致保守取值,别这么干
systemd 下正确配置 LimitNOFILE(Ubuntu/CentOS 7+)
直接改 my.cnf 不够,必须告诉 systemd:“这个服务允许开这么多文件”。否则 MySQL 进程一启动就被系统 cap 住。
- 运行
sudo systemctl edit mysql(或mariadb,看你的服务名),新建覆盖片段 - 写入:
[Service] LimitNOFILE=65535
- 保存后执行
sudo systemctl daemon-reload && sudo systemctl restart mysql - 验证:用
cat /proc/$(pgrep mysqld)/limits | grep "Max open files"查进程实际限制,再进 MySQL 执行SHOW VARIABLES LIKE 'open_files_limit';确认两者接近(MySQL 可能扣掉几十个用于内部句柄)
my.cnf 中 open_files_limit 的写法和优先级
配置项本身只在 MySQL 启动时读取一次,且仅当它 ≤ 系统允许上限时才可能生效。写法不对或位置错,等于没写。
- 必须放在
[mysqld]段下,不能放错段(比如放到[client]) - 值必须是纯数字,不要带单位(
65535✅,65535M❌) - 如果系统
ulimit是 4096,你配 65535,MySQL 日志里会写类似:Warning: Changed limits: max_open_files: 4096 max_connections: 151 table_cache: 400—— 这就是它被截断的证据 - 重启前建议先手动测试系统限制:
sudo -u mysql bash -c 'ulimit -n',确保输出是你期望的数字
为什么 SHOW VARIABLES 显示的值比 ulimit 小?
MySQL 不是简单照搬系统限制,它要预留一部分给自身线程、日志、临时表等内部使用。所以即使 ulimit -n 是 65535,open_files_limit 显示 64000 左右也正常。
- 影响实际可用数的关键不是 MySQL 配置,而是
table_open_cache和max_connections:每个连接可能打开多个表,每个表对应至少一个文件描述符 - 如果
table_open_cache设得太高(比如 16384),而open_files_limit只有 20000,MySQL 会频繁关闭再打开表文件,IO 压力陡增 - 查当前真实使用:
SHOW GLOBAL STATUS LIKE 'Open_tables';和SHOW GLOBAL STATUS LIKE 'Opened_tables';,后者持续增长说明缓存不够,但前提是open_files_limit没被卡住
ulimit → systemd LimitNOFILE → MySQL open_files_limit。漏掉任何一层,上层配置都白设。最容易被跳过的,就是 systemd 的 service 文件覆盖。










