Why your PHP-FPM throws 502 under load (pm.max_children, explained)

2026-10-26来源 dev.to DevOpsEnglish

Your PHP site runs fine, then traffic spikes and nginx starts throwing 502 Bad Gateway. Logs blame the upstream. The cause is almost always one number in your PHP-FPM pool: pm.max_children.

What actually happens

Nginx hands PHP requests to PHP-FPM. FPM has a fixed ceiling of worker processes — pm.max_children. When every worker is busy and the listen backlog fills, FPM can't accept the connection, nginx's fastcgi_pass fails, and the user gets a 502. Under pm = dynamic, you'll also see this in the FPM status page:

max children reached: 37 listen queue: 120 

That counter is the smoking gun: you've hit the ceiling 37 times.

How to size max_children (stop guessing)

The honest formula:

max_children = (RAM budget for FPM) / (average worker RSS) 
  • Measure a real worker's resident memory (RSS) under your actual app, not memory_limit (that's a cap, not usage).
  • Pick a RAM budget — total RAM minus what the DB, cache, and OS need. Leave headroom.
  • Divide. That's your ceiling. Set pm.max_children to it, not to a number you copied from a blog.

Too high and a traffic spike spawns more workers than RAM allows → the OOM killer starts reaping processes (worse than a 502). Too low and you 502 under load you could have served.

The shared-pool 502 storm

The nastiest version: multiple sites share one FPM master and one max_children. One busy site starves the others, and they all 502 — even the idle ones. Fix: give each site its own pool with its own ceiling, sized from its own RSS.

Also worth setting

  • pm.max_requests (recycle workers to bound memory leaks).
  • Watch slow requests in the status page and the slowlog — a few slow endpoints hold workers hostage and fake a capacity problem.

I turned this into a read-only CLI, fpm-doctor — it reads your pool configs + live status, measures real worker RSS, and recommends max_children from your actual memory budget, flags the shared-pool pattern, and ranks your slowlog. Composer + .phar, never writes your config.

原文:https://www.a8q9.cn/en/article/why-your-php-fpm-throws-502-under-load-pm-max-children-explained-e57456.html

相关文章