Introduction

PHP-FPM uses a pool of worker processes to handle incoming requests. When all workers are busy and the request queue is full, Nginx returns 502 Bad Gateway to clients. This happens during traffic spikes, when requests take longer than expected, or when the worker pool is undersized.

This is a common production issue that causes intermittent 502 errors under load while the server appears healthy otherwise.

Symptoms

  • Nginx returns "502 Bad Gateway" during peak traffic
  • PHP-FPM log shows "server reached pm.max_children, consider raising it"
  • Some requests complete normally while others fail with 502

Common Causes

  • pm.max_children is set too low for the concurrent request volume
  • Slow requests hold workers for extended periods, reducing available capacity
  • Memory limits force pm.max_children to be conservative

Step-by-Step Fix

  1. 1.Check current PHP-FPM status and worker utilization: Monitor worker count.
  2. 2.```bash
  3. 3.# Check PHP-FPM status (requires pm.status_path in pool config):
  4. 4.curl http://127.0.0.1:8080/fpm-status

# Output: # pool: www # process manager: dynamic # start time: 09/Apr/2026:10:00:00 +0000 # start since: 3600 # accepted conn: 15234 # listen queue: 5 <- Requests waiting in queue # max listen queue: 12 <- Peak queue depth # listen queue len: 128 <- Queue capacity # idle processes: 2 <- Available workers # active processes: 48 <- Busy workers # total processes: 50 <- Current total # max active processes: 50 <- Peak workers used # max children reached: 127 <- Times max was hit! ```

  1. 1.Tune PHP-FPM pool settings: Increase max_children based on available memory.
  2. 2.```ini
  3. 3.# /etc/php/8.2/fpm/pool.d/www.conf
  4. 4.[www]
  5. 5.; Calculate: available_memory / memory_per_process
  6. 6.; Example: 4GB RAM / 50MB per process = ~80 workers
  7. 7.pm = dynamic
  8. 8.pm.max_children = 80
  9. 9.pm.start_servers = 10
  10. 10.pm.min_spare_servers = 5
  11. 11.pm.max_spare_servers = 20
  12. 12.pm.max_requests = 500 ; Restart workers after 500 requests
  13. 13.pm.process_idle_timeout = 30s
  14. 14.request_terminate_timeout = 60s
  15. 15.`
  16. 16.Configure Nginx upstream queue: Buffer requests when PHP-FPM is at capacity.
  17. 17.```nginx
  18. 18.upstream php_backend {
  19. 19.server 127.0.0.1:9000;
  20. 20.# Increase the backlog queue
  21. 21.keepalive 32;
  22. 22.}

location ~ \.php$ { fastcgi_pass php_backend; fastcgi_read_timeout 60s; fastcgi_connect_timeout 10s; fastcgi_send_timeout 30s; } ```

Prevention

  • Monitor PHP-FPM "max children reached" metric and alert when > 0
  • Size pm.max_children based on actual memory usage per process
  • Set request_terminate_timeout to prevent slow requests from blocking workers
  • Use pm.max_requests to periodically recycle workers and prevent memory leaks