PHP-FPM (FastCGI Process Manager) manages a pool of worker processes that handle PHP requests for WordPress, and its default configuration is tuned for low-memory shared hosting rather than a dedicated server serving hundreds of concurrent visitors. The two most critical settings are pm (process manager mode) and pm.max_children (the worker limit) — misconfiguring either causes either idle memory waste or request queuing that makes the site appear slow. pm = dynamic starts a small number of idle workers and scales up to pm.max_children under load, which is suitable for sites with variable traffic patterns. pm = static maintains a fixed number of workers at all times, trading memory for faster response at sustained high concurrency. The correct pm.max_children value is calculated from available RAM: divide the RAM reserved for PHP-FPM by the average memory footprint of one WordPress request, typically 40–80 MB depending on active plugins. Setting pm.max_requests to a value like 500 restarts each worker process periodically, preventing memory leaks in long-running PHP processes from accumulating indefinitely. request_terminate_timeout kills PHP processes that exceed a wall-clock limit, preventing a single slow database query or external API call from consuming a worker indefinitely and starving other requests. The slowlog and request_slowlog_timeout settings mirror the MySQL slow query log concept for PHP — they record the PHP call stack of any request that exceeds the threshold, pointing directly to slow WordPress hooks or plugin code. The Nginx FastCGI cache post explains how caching reduces the number of PHP-FPM workers needed — fewer workers can serve more traffic when most requests are satisfied from cache. The MySQL slow query log guide should be enabled alongside the PHP-FPM slowlog so you can correlate slow PHP requests with the underlying slow database queries that cause them. Reload PHP-FPM with systemctl reload php8.1-fpm (no restart needed) to apply pool setting changes without dropping active connections.
Problem: Default PHP-FPM pool settings allocate too few worker processes for high-traffic WordPress sites or too many for low-memory VPS servers, causing either request queuing under load or unnecessary RAM exhaustion at idle.
Solution: Calculate pm.max_children from available RAM, set pm = dynamic with appropriate start, min-spare, and max-spare values, and enable the PHP-FPM slowlog to identify slow WordPress requests by their call stack.
# /etc/php/8.1/fpm/pool.d/wordpress.conf
[wordpress]
user = www-data
group = www-data
listen = /run/php/php8.1-fpm-wordpress.sock
listen.owner = www-data
listen.group = www-data
; Dynamic: scales between min and max_children based on demand
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.max_requests = 500
; Kill requests running longer than 30 seconds
request_terminate_timeout = 30s
; Log PHP call stack for requests slower than 2 seconds
slowlog = /var/log/php-fpm/wordpress-slow.log
request_slowlog_timeout = 2s
; Per-request memory limit (override php.ini for this pool)
php_admin_value[memory_limit] = 256M
php_admin_value[error_log] = /var/log/php-fpm/wordpress-error.log
; Formula: pm.max_children = RAM_for_FPM / avg_request_memory
; Example: 1600 MB / 80 MB = 20 max_children
NOTE: Check the actual memory usage of each PHP-FPM worker with ps aux --sort=-%mem | grep php-fpm | head -n 10 — the RSS column in megabytes is the per-process footprint. Divide available server RAM (after OS and MySQL) by that value to calculate the correct pm.max_children for your specific plugin stack.