How to fix 'Too many open files' on Linux for PHP‑FPM during traffic spikes
By Kevin Marcondes · Published on · 7 min read
How to fix 'Too many open files' on Linux for PHP‑FPM during traffic spikes: understand what exhausts file descriptors (FDs), how to diagnose it in production, and which adjustments to apply at each layer (systemd, kernel, FPM, Nginx). Below are practical steps to stabilize systems without promising miracles.
Real symptoms and when this error shows up
It happens at traffic peaks, when PHP‑FPM accepts new connections while holding FDs open: sockets, log files, temp files and upstream connections. Symptoms include 502/504 from Nginx, intermittent API failures and 'Too many open files' messages in FPM and web server logs.
Do not confuse this with ephemeral port exhaustion. Here the issue is the file descriptor ceiling for the process, the service or the kernel.
- 502/504 and brief outages under load.
- ‘Too many open files’ entries in PHP‑FPM logs.
- Increased latency and request queues at the web server.
- Database and cache connections failing due to insufficient FDs.
Immediate diagnosis in production (stay calm)
Do three checks: 1) confirm the error in logs; 2) inspect the effective FD limit of the FPM master; 3) count open FDs to see the gap. This tells you which layer needs adjustment. If you already export metrics, correlate FPM queueing with FD usage — see how to expose PHP‑FPM metrics.
# 1) Confirme no log do FPM
sudo grep -i "too many open files" /var/log/php*-fpm*.log || true
# 2) Descubra o PID do master do PHP-FPM
pgrep -x "php-fpm" || pgrep -x "php-fpm8.2" || pgrep -x "php-fpm7.4"
PID=<<coloque_o_pid_aqui>>
# Limites efetivos do processo (procfs)
cat /proc/$PID/limits | grep -i "open files"
# Também veja o LimitNOFILE do unit systemd correspondente
systemctl show php-fpm --property=LimitNOFILE 2>/dev/null || \
systemctl show php8.2-fpm --property=LimitNOFILE 2>/dev/null
# 3) Quantos FDs o master mantém abertos agora?
lsof -p $PID | wc -l
# Tipos mais comuns de FDs (visão rápida)
lsof -p $PID | awk '{print $5}' | sort | uniq -c | sort -nr | head -n 10
Where the limit comes from: layers that control FDs
The FD ceiling is the combination of kernel, service manager and app. Changing only the shell ulimit does not affect services managed by systemd. Understand the stack before making changes.
| Layer | Where to change | Main parameter | How to check |
|---|---|---|---|
| Kernel (global) | /etc/sysctl.d/*.conf | fs.file-max | sysctl fs.file-max |
| Systemd (service) | unit override | LimitNOFILE | systemctl show <unit> --property=LimitNOFILE |
| PHP‑FPM (pool) | www.conf (or pool file) | rlimit_files | /proc/$PID/limits (Open files) |
| Nginx (worker) | nginx.conf | worker_rlimit_nofile | nginx -T | grep rlimit |
| Shell/PAM (login) | /etc/security/limits*.conf | nofile | ulimit -n (in interactive session) |
| Containers (Docker) | compose.yaml / run | ulimits: nofile | docker inspect ... | jq '.[0].HostConfig.Ulimits' |
Quick fix focused on the service (systemd + FPM)
Increase LimitNOFILE in the PHP‑FPM unit and optionally set rlimit_files in the pool. This requires a service restart because limits are applied when the process is created. To reduce user impact, consider a traffic shift using a blue‑green deploy pattern before restarting.
- Use a value with headroom for the expected peak.
- Check logs after restart to confirm.
- Do not exceed the kernel capacity (fs.file-max).
# 1) Override no systemd
sudo systemctl edit php-fpm || sudo systemctl edit php8.2-fpm
# Adicione no editor que abrir:
# [Service]
# LimitNOFILE=131072
sudo systemctl daemon-reload
sudo systemctl restart php-fpm || sudo systemctl restart php8.2-fpm
# 2) (Opcional) rlimit_files no pool do FPM
# Em /etc/php/*/fpm/pool.d/www.conf ou similar:
# rlimit_files = 131072
# Depois, reinicie o PHP-FPM novamente.
# Valide
systemctl show php-fpm --property=LimitNOFILE 2>/dev/null || \
systemctl show php8.2-fpm --property=LimitNOFILE 2>/dev/null
cat /proc/$(pgrep -x php-fpm | head -n1)/limits | grep -i "open files"
Persistent adjustments and safe scaling
Ensure the kernel and the service can support the new ceiling. Adjust fs.file-max and review FPM pool parameters to avoid uncontrolled growth. Do not raise limits without monitoring CPU, memory and I/O, otherwise you may simply move the bottleneck elsewhere.
- Kernel: increase fs.file-max persistently.
- FPM: review pm.max_children and pm.process_idle_timeout.
- Logs: proper rotation avoids too many log FDs being held open.
# Kernel: persistir um teto global mais alto
echo 'fs.file-max = 1000000' | sudo tee /etc/sysctl.d/99-fd.conf
sudo sysctl --system
# PHP-FPM (pool): além de rlimit_files, confira a capacidade de workers
# Ex.: pm = dynamic; pm.max_children = <valor_compatível_com_recursos>
# Consulte a documentação oficial do PHP-FPM para detalhes dos parâmetros.
Nginx, connections and interplay with containers (Docker)
If Nginx proxies to FPM, its workers also need a higher ceiling. In containers, define ulimits per service. Note that container limits do not inherit from the host by default. If you're evaluating reverse proxies, see criteria in Traefik vs Nginx.
- Nginx: adjust worker_rlimit_nofile and worker_connections.
- Docker: set ulimits:nofile in compose or run options.
- Orchestrators enforce their own limits; review manifests.
# docker-compose.yml (exemplo)
services:
php-fpm:
image: php:8.2-fpm
ulimits:
nofile:
soft: 131072
hard: 131072
nginx:
image: nginx:stable
ulimits:
nofile:
soft: 131072
hard: 131072
Prevention: metrics, logs and load testing
Stabilize operations with visibility and dry runs of peak load. Measure FDs and the FPM queue, centralize logs and test changes before critical hours. Combine FD alerts with traffic charts to anticipate saturation.
- Metrics and dashboards: set up Prometheus and Grafana.
- Structured logs and correlation under load: structured JSON logs & correlation.
- Zero‑downtime traffic shift when restarting services: blue‑green deploy.
- Containers: combine ulimits with cgroups. Guide: cgroup v2 + systemd.
Post‑fix checklist
Confirm the new limits are active and that the app sustains the simulated peak. Do not run uncontrolled load tests in production. Use a maintenance window, limits and real‑time monitoring.
- Unit LimitNOFILE is correct.
- /proc/$PID/limits reflects the new ceiling.
- lsof under load stays below the limit.
- Nginx and containers adjusted as well.
- Logs show no new 'Too many open files' entries.
systemctl show php-fpm --property=LimitNOFILE 2>/dev/null || \
systemctl show php8.2-fpm --property=LimitNOFILE 2>/dev/null
PID=$(pgrep -x php-fpm | head -n1)
cat /proc/$PID/limits | grep -i "open files"
# Simule carga leve e observe:
watch -n2 "lsof -p $PID | wc -l"
Frequently asked questions
What causes 'Too many open files' in PHP‑FPM?
The process hit its file descriptor ceiling. This includes sockets, log and temp files. During spikes, each worker holds multiple FDs, summing across the service LimitNOFILE, pool rlimit_files and the kernel fs.file-max.
Is increasing the shell ulimit enough to fix it?
No. Services managed by systemd ignore the ulimit from your interactive session. You must set LimitNOFILE in the service unit and optionally rlimit_files in the PHP‑FPM pool, and ensure an appropriate fs.file-max at the kernel level.
Do I need to restart PHP‑FPM after changing limits?
Yes. Limits like LimitNOFILE and rlimit_files are applied when the process starts. A reload does not change them. Plan a safe restart, draining connections via a reverse proxy to avoid user errors.
What are the risks of setting very high limits?
If limits are raised without matching resources (CPU/RAM/I/O), the server may accept too much work and degrade. The kernel also has a global ceiling (fs.file-max). Increase with reasonable headroom and monitor usage to calibrate.
How do I adjust limits in Docker Compose environments?
Define ulimits:nofile per service in compose or when running containers. Adjust Nginx and PHP‑FPM separately. Host limits are not automatically applied to containers—verify with docker inspect and monitor under load.
Need help stabilizing PHP‑FPM under load?
Guided diagnosis, layered limit adjustments and validations with observability. Let's discuss your environment and practical next steps.
Talk about my environmentSee also
- Intermittent 502 Bad Gateway in Docker Compose with Nginx & PHP‑FPM: how to diagnose and fix timeouts and connection overloads
- How to diagnose and capture packets for intermittent network issues between Docker containers on Debian
- How to detect and fix duplicate SKU inconsistencies between WooCommerce and your ERP without losing orders
- How to reduce build time and avoid duplicate artifacts in CI for large PHP monoliths