When a PHP website starts to slow down, the first assumption usually points to inadequate hosting. However, the problem is often more specific: all PHP-FPM workers are busy, while new requests must wait their turn.
PHP-FPM or PHP FastCGI Process Manager is a process manager that runs PHP applications behind web servers like Nginx. Think of PHP-FPM as a service counter. pm.max_children determines how many counters can work simultaneously. If all counters are occupied, the next visitor enters the queue.
PHP-FPM is indeed designed for high-load sites and provides process settings, status, and slowlog to assist in diagnosis. ([php.net](https://www.php.net/manual/en/install.fpm.php/install.php?utm_source=openai))
Symptoms of a Slow Website Due to PHP-FPM Queue
This issue usually appears with a somewhat confusing pattern. Static pages like images or CSS files remain fast, but pages that require PHP feel heavy. During peak hours, wait times increase, and some requests end with a gateway timeout error.
The server's CPU may not necessarily be at 100 percent. In fact, the server can appear quite relaxed because the bottleneck is not a lack of computational power, but rather the number of available workers. If one request takes five seconds and all workers are running similar processes, new requests still have to wait even if the CPU is not full.
Some signs to check:
- The
listen queuevalue is often greater than zero. max children reachedindicates that the process limit has been reached at some point.- The number of active processes is consistently approaching
pm.max_children. - Application or PHP-FPM logs record many slow requests.
- Nginx occasionally returns a 504 Gateway Timeout.
Don't Immediately Increase pm.max_children
pm.max_children is not a number that the larger, the better. Each PHP process requires memory. If the value is increased without considering the available RAM, the server can experience memory pressure, start using swap, or even forcibly terminate processes.
A simple initial estimate is to divide the realistic memory available for PHP by the average memory usage of one PHP process:
pm.max_children = memory for PHP / average RAM per PHP processFor example, if about 1,200 MB is available for PHP and one worker averages 80 MB, the theoretical limit is around 15 workers. This number is not a final configuration as it still needs to leave room for Nginx, the database, the operating system, cache, and other processes.
Measure actual usage during normal load and peak times. Workers that seem light on simple pages can be much more resource-intensive when processing reports, complex searches, data imports, or third-party plugins.
How to Read PHP-FPM Status
PHP-FPM provides a status page that can display the number of accepted connections, the queue waiting, active processes, idle processes, peak memory usage, and the number of slow requests. This information is much more useful than just looking at CPU graphs.
Example configuration for the PHP-FPM pool:
pm.status_path = /fpm-status
ping.path = /fpm-pingOnce the status page is available, pay particular attention to the following three things:
- listen queue. If the value frequently rises, requests are waiting for an available worker.
- max children reached. If the value is greater than zero, the process limit has been touched since PHP-FPM started.
- slow requests. This number helps indicate that some requests exceed the defined slowlog threshold.
The status page should not be open to the public. PHP documentation warns that this page reveals resource information and should be restricted to localhost, internal networks, or monitoring IP addresses. ([php.net](https://www.php.net/fpm.status.php?utm_source=openai))
Find Requests That Hold Up Workers
Increasing the number of workers only masks the problem if the root cause is slow requests. A single page can hold up a worker by running a database query without an index, calling an unresponsive external API, processing large images, or doing heavy work directly within the user request.
Enable slowlog with a reasonable timeout in an appropriate environment:
request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm/www-slow.logSlowlog can help show the execution trace of PHP when requests take too long. After identifying the problematic endpoint, measure its components: MySQL query time, API calls, template processing, and file operations.
For tasks that do not need to be completed before the user receives the page, consider moving them to a job queue or background process. Sending emails, generating PDF reports, or processing multiple images in the main request often exhausts workers quickly.
The Role of Nginx: Timeout Is Not a Performance Solution
Nginx has settings like fastcgi_read_timeout to determine how long to wait for a response from PHP-FPM. The documented default value is 60 seconds, but increasing the timeout does not make PHP faster. It merely gives requests more time before being considered failed. ([nginx.org](https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html?utm_source=openai))
A timeout that is too short can cut off legitimate processes, such as small data exports that take longer. However, a timeout that is too long can also hold up workers and lengthen the queue. Use timeouts as a safety net, not as a substitute for code optimization.
Strategies for pm to Understand
PHP-FPM has several worker management models. The dynamic mode maintains a number of initial processes and adds processes as needed. The ondemand mode creates processes when there is a request and can stop them when idle. The static mode maintains the number of processes according to configuration.
For many typical websites, dynamic is often a reasonable starting point. However, the best choice depends on traffic patterns, RAM capacity, and how often the application experiences request spikes.
The pm.max_requests setting is also worth noting. This value determines how many requests each child process serves before the process is recreated. PHP documents this setting as one way to reduce the impact of memory leaks from third-party libraries. ([php.net](https://www.php.net/manual/tr/install.fpm.configuration.php?utm_source=openai))
What You Can Do Now
- Enable PHP-FPM status in a limited manner for internal addresses or monitoring IPs.
- Record the
listen queue, active processes, andmax children reachedvalues during normal and peak hours. - Enable slowlog to find endpoints that hold workers too long.
- Check database queries, external APIs, upload processes, and heavy work in those requests.
- Recalculate
pm.max_childrenbased on actual RAM, not by copying numbers from other servers. - Set Nginx timeouts reasonably after understanding the duration of necessary requests.
In essence, a full PHP-FPM is a symptom, not a final diagnosis. Sometimes the solution is indeed to add workers. However, more often, the best results come from shortening slow requests, moving heavy work to background processes, and monitoring the queue before users start to complain.
Sources & Further Reading
- PHP: FastCGI Process Manager (FPM)
- PHP-FPM Configuration Manual
- PHP-FPM Status Page
- Nginx FastCGI Module Documentation
– Rio Yotto @rioyotto
