Skip to main content

PHP-FPM

Updated: October 30, 2026
By Willya Randika

PHP-FPM (FastCGI Process Manager) runs PHP as a separate process that takes work over FastCGI from a web server such as Nginx or Apache. Compare that with PHP as an Apache module: in module mode the code runs inside the web server process, while in FPM a master process manages a pool of workers. Each worker serves one script at a time, so concurrency equals the number of workers in the pool. Because every worker loads its own PHP engine and application, FPM needs more careful memory planning than a module.

The master and worker model

The master reads the pool config and keeps the worker count within the rules. pm.max_children is the practical ceiling: that many workers may be alive at once, and it is what limits how many PHP requests are served simultaneously. pm.start_servers, pm.min_spare_servers, and pm.max_spare_servers apply only in dynamic mode; static pins a fixed count, and ondemand starts a worker only when asked.

Configuring the pool

On a VPS the pool lives in a www.conf file, and edits take effect only after FPM reloads, for example systemctl reload php-fpm. Size pm.max_children by dividing the RAM reserved for PHP by the average per-worker usage, not by picking the biggest number that fits. systemctl status php-fpm tells you whether the service is up and workers are running. Raising max_children as high as possible just moves the problem from a queue to memory: once RAM is gone the server swaps, and swapping makes the site slower than a short wait ever would.

Watching a live pool

Enable pm.status_path and you can open the status endpoint to see active processes, idle workers, and how often the pool has hit pm.max_children. On CloudLinux hosts, the panel's resource page shows per-account usage. The clearest signal is in the FPM log: server reached pm.max_children setting means the pool is too small or the scripts are too slow.

When workers run out

Once every worker is busy, new requests wait in the backlog; if the backlog fills, the server refuses them with an HTTP 503. This is easy to misread: the workers are exhausted, not the RAM or CPU, so a resource monitor can look fine while the site crawls. On shared hosting the same idea arrives as an Entry Processes cap, and LiteSpeed uses an LSAPI mechanism that plays a similar role.

What pins a slot too long

A single stuck process can look like a big problem. A worker waiting on a slow query or an external API call holds its slot until it finishes, and a handful of stuck workers can drain the whole pool. On shared hosting that same process also occupies an entry-process slot while it waits, for example a cron job hitting a heavy URL over and over. That is why the symptom is often intermittent: fine when quiet, jammed at peak.

FAQ

How do I know the PHP-FPM pool is saturated?

You see server reached pm.max_children setting in the log, or a 503 during traffic spikes while CPU and RAM still look free. Both point to exhausted workers rather than a memory shortage.

Should I raise pm.max_children as high as it goes?

No. Size it from the RAM reserved for PHP divided by average per-worker usage. Overstating it exhausts RAM and pushes the server into swap, which slows everything down.

Can .htaccess change the FPM pool?

No. Pool settings live in the FPM config files and only apply after a reload. php_value in .htaccess is accepted by the mod_php handler, not FPM.

Disclaimer: Hosting Wiki articles are prepared for educational and reference purposes. Hosting technology keeps evolving, so some technical details may change over time.