Linux  ·  high  ·  Web, PHP & databases

"server reached pm.max_children setting" — the site stalls under load

Every worker is busy, so requests queue. The site is not down; it is fully occupied.

What you see

The site becomes slow at busy times, then returns 504. The warning appears in the php-fpm log at the same moment.

What is actually wrong

Either genuine traffic growth beyond the configured worker count, or each request taking far longer than it should — usually a slow database query or an external API call with no timeout.

Codes and articles

pm.max_childrenserver reached max_children504 Gateway Time-outWARNING: [pool www]

Fixes (2)

Find what is holding the workers
Root shell40 minuteslow riskreversible

Before adding workers. More workers running the same slow query just moves the queue into the database.

  1. Turn on the status page and watch it under load.

    Shell
    grep -n 'pm.status_path' /etc/php/8.2/fpm/pool.d/www.confcurl -s http://localhost/fpm-status?full | head -40
  2. Enable the slow log if it is not on, then read what it catches.

    Shell
    sudo tail -50 /var/log/php-fpm-slow.log

    The slow log records a full stack trace of what each stuck request was doing at the moment it passed the threshold. It usually names one query or one HTTP call, and that is the actual fault.

  3. Check the database for queries that are running long.

    Shell
    mysql -e "SELECT id,user,host,db,command,time,state,LEFT(info,80) FROM information_schema.processlist WHERE time > 2 ORDER BY time DESC\G"
  4. Add a timeout to any outbound HTTP call in the application. A request to a third party with no timeout holds a worker until the kernel gives up, which can be minutes.

  5. Fix the slow query — usually a missing index — before touching the pool configuration.

Confirm it workedThe slow log is quiet and active workers stay well below the maximum at peak.
If you need to undo itNothing was changed on the server itself.
Size the pool for the memory available
Root shell30 minutesmedium riskreversible

Requests are reasonable and there are genuinely more of them.

  1. Measure what one worker actually uses rather than guessing.

    Shell
    ps -o rss=,comm= -C php-fpm8.2 | awk '{s+=$1; n++} END {printf "workers=%d avg=%dMB\n", n, s/n/1024}'

    The right value is available memory divided by the real per-worker figure, leaving room for the database and the operating system. A number copied from a blog post is how servers end up swapping under load, which is far worse than queueing.

  2. Check total memory and what else is using it.

    Shell
    free -mps -eo rss,comm --sort=-rss | head -10
  3. Set the values consistently — max_children is the ceiling, and the start/min/max spare values must be below it.

    Shell
    sudo sed -i 's/^pm.max_children.*/pm.max_children = 30/; s/^pm.start_servers.*/pm.start_servers = 8/; s/^pm.min_spare_servers.*/pm.min_spare_servers = 5/; s/^pm.max_spare_servers.*/pm.max_spare_servers = 12/' /etc/php/8.2/fpm/pool.d/www.conf
  4. Add a request limit so a leaking worker is recycled rather than growing forever.

    Shell
    sudo sed -i 's/^;*pm.max_requests.*/pm.max_requests = 500/' /etc/php/8.2/fpm/pool.d/www.confsudo systemctl reload php8.2-fpm
  5. Confirm the machine does not swap under peak load — if it does, the number is too high regardless of what the calculation said.

    Shell
    vmstat 2 10
Confirm it workedThe warning stops appearing and free memory stays positive at peak.
Shell
sudo grep -c max_children /var/log/php8.2-fpm.log
If you need to undo itRestore the previous values in www.conf and reload.

Where this stops. This write-up was written and checked by hand. It says what each step changes, how to confirm it worked and how to reverse it, and anything destructive is flagged before you reach it. If it does not match what your machine is doing, search the Support Centre for the exact code or message — and when something needs a person, get in touch.