结论:too many open files 是系统级文件描述符四层限制未对齐所致,必须同步配置内核fs.file-max、用户limits.conf(含pam启用)、systemd limitnofile(如适用)及nginx.conf中worker_rlimit_nofile与worker_connections关系,缺一不可。

直接说结论:Too many open files 不是 Nginx 单独的问题,而是系统级文件描述符(file descriptor, FD)层层限制没对齐导致的。只改 nginx.conf 或只跑 ulimit -n 65535 都会失效——必须完成「内核 → 用户限制 → 进程启动环境 → Nginx 配置」四层闭环。
查清当前各层 FD 限制值,别猜
错误常发生在“明明改了 limits.conf,重启 Nginx 还报错”。根本原因是:你看到的 ulimit -n 是当前 shell 的软限制,而 Nginx master 进程实际继承的是其启动用户的 limits,worker 进程又可能受 worker_rlimit_nofile 约束。必须逐层验证:
- 系统全局上限:
cat /proc/sys/fs/file-max(内核级,建议设为 ≥ 200000) - 当前用户软硬限制:
ulimit -Sn和ulimit -Hn(注意:Nginx 若以nginx用户运行,就得用该用户身份执行) - Nginx master 进程实际限制:
cat /proc/$(cat /var/run/nginx.pid)/limits | grep "Max open files" - Nginx worker 进程限制:
ps --ppid $(cat /var/run/nginx.pid) -o %p | sed '1d' | xargs -I{} cat /proc/{}/limits | grep "Max open files"
如果 worker 进程显示仍是 1024 4096,说明前面某一层没生效,别急着调 worker_connections。
/etc/security/limits.conf 修改后不生效?重点看三件事
这是最常踩的坑。改完 /etc/security/limits.conf 却发现 ulimit -n 还是 1024,大概率卡在这三个地方:
- 没指定具体用户:用
*是全局,但若 Nginx 以nginx用户运行,更稳妥写法是单独加两行:nginx soft nofile 65535和nginx hard nofile 65535 - PAM 模块未启用:确认
/etc/pam.d/common-session(Debian/Ubuntu)或/etc/pam.d/login(CentOS/RHEL)里有session required pam_limits.so;缺这句,limits.conf 形同虚设 - 没重新登录或没用新会话启动:修改后必须用新 shell 登录,或用
su - nginx -c 'ulimit -n'验证;systemd 启动的 Nginx 还需检查LimitNOFILE是否覆盖了 limits.conf
nginx.conf 中 worker_rlimit_nofile 和 worker_connections 的关系
worker_rlimit_nofile 不是并发连接数,它是每个 worker 进程能打开的**最大文件描述符总数**,包括日志、配置文件、socket、临时文件等。而 worker_connections 是它能处理的**并发网络连接数**。两者必须满足:
worker_rlimit_nofile ≥ worker_connections × worker_processes + 预留余量(至少 +1024)- 例如:4 核机器设
worker_processes auto(即 4),worker_connections 8192,那worker_rlimit_nofile至少要设为8192 × 4 + 1024 = 33792,建议直接设65535 - 如果
worker_rlimit_nofile小于理论所需,Nginx 启动时不会报错,但运行中 accept() 就会失败并打日志:accept() failed (24: Too many open files)
systemd 启动 Nginx 时 limits.conf 被绕过?加 LimitNOFILE
现代 Linux 发行版多用 systemd 管理 Nginx,它默认忽略 /etc/security/limits.conf。此时必须显式设置:
- 编辑
/etc/systemd/system/multi-user.target.wants/nginx.service或运行systemctl edit nginx - 添加如下内容:
[Service] LimitNOFILE=65535
- 然后执行:
systemctl daemon-reload && systemctl restart nginx - 验证:用
systemctl show nginx | grep LimitNOFILE确认值已加载;再查 worker 进程的/proc/PID/limits是否同步
这个环节最容易被忽略——尤其在 CentOS 8+/Ubuntu 20.04+ 环境下,不加 LimitNOFILE,前面所有 limits.conf 配置都白做。











