PHP-FPM Production Pool Tuning for High-Traffic Linux Servers
Performance

PHP-FPM Production Pool Tuning for High-Traffic Linux Servers

  • Author :Liam K.
  • Date :June 30, 2026
  • Time :16 minutes

PHP-FPM pool misconfiguration is one of the most common causes of 502 errors, memory exhaustion, and unpredictable latency on Linux web servers. The right worker count depends on available RAM, per-request memory footprint, and concurrency — not generic defaults. This guide shows how to size and tune pools for production traffic.

Step 1: Measure Per-Worker Memory

Run your application under realistic load, then measure RSS per PHP-FPM child process.

bash
ps -ylC php-fpm8.3 --sort=rss | awk 'NR==1{print} NR>1 && NR<=15{print}'
# Example output: each worker ~85 MB RSS for a typical Laravel app

Step 2: Calculate Safe max_children

Reserve 20–30% RAM for OS, database, cache, and Nginx. Formula: max_children ≈ (available RAM for PHP) / average worker RSS.

bash
# Example: 8 GB RAM server, reserve 2 GB for system + DB + cache
# Available for PHP: 6 GB = 6144 MB
# Worker RSS: 85 MB
# max_children ≈ 6144 / 85 ≈ 72 (use 60–65 for headroom)

Step 3: Configure a Dynamic Pool

bash
sudo tee /etc/php/8.3/fpm/pool.d/www.conf >/dev/null <<'EOF'
[www]
user = www-data
group = www-data
listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
[...]
Command truncated. Copy to view full command.

Step 4: Tune OPcache for Production

bash
sudo tee /etc/php/8.3/fpm/conf.d/10-opcache.ini >/dev/null <<'EOF'
opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=256
opcache.interned_strings_buffer=32
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
opcache.revalidate_freq=0
[...]
Command truncated. Copy to view full command.

Set opcache.validate_timestamps=0 only when you reload PHP-FPM after each deploy. For development, keep validation enabled.

Step 5: Add Nginx FastCGI Timeouts

nginx
# Inside your PHP location block:
fastcgi_connect_timeout 10s;
fastcgi_send_timeout 60s;
fastcgi_read_timeout 60s;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;

Step 6: Validate and Reload

bash
sudo php-fpm8.3 -t
sudo systemctl reload php8.3-fpm
sudo systemctl reload nginx

# Watch pool status during load test
watch -n 2 'ps -ylC php-fpm8.3 | wc -l'

Step 7: Monitor Slow Requests

bash
sudo tail -f /var/log/php8.3-fpm-slow.log

# Enable php-fpm status page (restrict to localhost):
# pm.status_path = /fpm-status
# ping.path = /fpm-ping

Common Mistakes to Avoid

  • Setting pm.max_children too high — causes OOM kills under traffic spikes.
  • Using pm = ondemand for latency-sensitive APIs without measuring cold-start cost.
  • Ignoring pm.max_requests — long-lived workers can leak memory over days.
  • Deploying code changes without reloading PHP-FPM when OPcache timestamp validation is disabled.
  • Running multiple heavy PHP apps in one pool instead of separate pools per site.

"PHP-FPM tuning is arithmetic, not guesswork: measure worker memory, size the pool, then validate under load before you trust it in production."

Technical Author

Technical Author - Liam K.
Liam K.

System administrator and technical writer specializing in server infrastructure, security and deployment. Creating comprehensive guides to help you master server administration.