PHP-FPM pool tuning in production — the static vs dynamic vs ondemand decision
May 12, 2026 · 1 min read · by Sudhanshu K.
The single most common PHP performance issue on incoming audits: PHP-FPM in dynamic mode with default sizing that was appropriate for a 1GB VPS in 2014, running on a 16GB box, while the application is starving at 5 children. The other common one: pm = ondemand on a high-RPS production site that pays the fork cost on every burst.
This is the pool tuning we apply during onboarding, the slowlog discipline we enforce afterward, and how to know if it's working.
The pool we usually ship
; /etc/php/8.3/fpm/pool.d/www.conf
pm = static
pm.max_children = 50
pm.max_requests = 1000
request_terminate_timeout = 60s
request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm/slow.log
pm.status_path = /fpm-status
ping.path = /fpm-pingstatic once you know the right max_children — no fork cost on bursts, predictable memory. Calculate max_children as (available RAM - OS overhead - other services) / per-process memory. Measure per-process memory under load, not at idle.
The full write-up covers:
- The pm modes — static vs dynamic vs ondemand, and when each is right
- Calculating
pm.max_childrenfrom observed per-process memory under load pm.max_requestsand why setting it to 0 (default) is wrong- Slowlog tuning — the 5-second threshold and the patterns it surfaces
- The
/fpm-statusNginx wiring and what each metric means - Coordinating PHP-FPM tuning with the OPcache + JIT config on the same host
We ship this configuration on every managed PHP stack.
Full article available
Read the full article