To plan PHP-FPM capacity effectively, first calculate how many workers will fit within the available RAM budget. Separately, estimate how many workers are needed to handle the traffic actually arriving at the pool. pm.max_children It limits the number of workers available simultaneously per pool, but it is neither a visitor count nor a direct throughput value. CPU, database, and peak loads also determine which setting is viable in production.
What Limits a PHP-FPM Worker
PHP-FPM manages PHP processes in pools. A Worker processes one request at a time; the pool setting pm.max_children Limits the number of workers available at any given time and, consequently, the number of PHP requests that this pool can process simultaneously. If there are multiple pools, the limit applies to each individual pool, not automatically to the entire server.
This number is neither the number of logged-in visitors nor a direct measure of requests per second. A visitor can trigger multiple requests, while a logged-in user does not occupy a worker between two actions. Conversely, a single slow request can tie up a worker for longer than several short requests in a row.
Not every page view reaches PHP-FPM either. If the web server serves a static file directly or if an upstream cache fully fulfills a request, a PHP worker may not be necessary, depending on the architecture. Cache misses, logged-in users, and administrative pages, on the other hand, can still generate PHP requests and temporarily increase resource utilization.
For capacity planning, therefore, two separate questions are crucial: How many workers, including a reserve, can fit into the available RAM? And how many workers does the traffic actually arriving at the pool require so that requests do not have to wait excessively long? A high value for pm.max_children does not answer any of these questions on its own.
Even if sufficient memory is available, the CPU, database, or external services may limit the practical capacity. While additional workers allow for more parallel PHP processing, they can simultaneously increase the load on an already slow service. The pool value is therefore an operational limit and not a performance guarantee.
Understanding Process Managers and Queues
The Process Manager Specifies when PHP-FPM provisions workers. When static the reserved process count corresponds to the value of pm.max_children. This makes it easy to plan the number of processes, but it also ties up resources even when the system is underutilized. The upper limit itself must still be consistent with the available memory.
At dynamic FPM adjusts the number of processes: The initial count, as well as the minimum and maximum number of free workers, are also set. When ondemand Workers are created only when needed and are terminated after a configured idle period. This can save resources in pools that are rarely used; however, in the event of a sudden load spike, new processing capacity must first be created.
| Mode | Important Settings | Application and Consideration |
|---|---|---|
| static | pm.max_children | Fixed number of workers; easy to plan, but resources are tied up when idle. |
| dynamic | pm.max_children, pm.start_servers, pm.min_spare_servers, pm.max_spare_servers | Adapting to changing demand; idle and newly started workers must be coordinated. |
| ondemand | pm.max_children, pm.process_idle_timeout | Workers on demand; saves resources in rarely used pools; process starts must be taken into account when the load increases. |
If all workers are busy, additional requests can be placed in the Listener Queue wait for a free process. The FPM status shows, among other things, the current and maximum queue lengths. However, a single high maximum value does not indicate whether the pool is currently overloaded; to determine that, it needs to be viewed over time.
A larger queue does not create additional workers or speed up a slow database. It can temporarily absorb requests, but merely shifts the wait time to before PHP processing. Therefore, both the typical load pattern and the consequences of short spikes are important when deciding on a process manager.
Classifying Worker Memory Correctly
A worker's memory requirements cannot be reliably determined based solely on a PHP configuration limit. Process data collected under appropriate load conditions is more helpful for planning purposes. It makes a difference whether you are looking at the resident memory of a single process or trying to estimate the memory usage of an entire group of PHP-FPM workers.
RSS describes a process's resident memory. If multiple workers use the same memory pages, those pages may be included in each worker's RSS. If you add up the RSS values of all workers, shared pages may appear multiple times; therefore, the sum does not provide an accurate picture of the physical memory shared among them.
PSS distributes shared pages proportionally among the participating processes. The sum of the PSS values for a process group is therefore often more useful for its memory planning than the sum of the RSS values. Nevertheless, it remains a snapshot: If the number of processes sharing pages changes, their respective shares also change.
Consider multiple workers for both typical and memory-intensive requests. A newly started process or a single average may underestimate future demand. The total pool PSS for different numbers of workers and load conditions helps derive a conservative estimate; extrapolating this to more workers remains uncertain due to variable shared and private portions.
The PHP-memory_limit is not a reliable indicator of the total operating system memory used by an FPM process and does not replace this observation. You should not automatically deduct shared memory—such as that used by OPcache—a second time from the budget if it is already included proportionally in the used pool PSS. Other services and a reserve must still be taken into account.
Calculate RAM Budget and Number of Workers
The starting point is the actual available RAM: on a host, this is the memory available for services; in a container, it is the effective memory limit. Subtract from this the memory requirements of the operating system, the web server, any local database, and other services. Other FPM pools and a reserve for fluctuating usage should also be factored into the calculation.
The remaining portion is the Pool Budget. To estimate the number of workers, observe the PSS sum of the pool workers at various process counts and load conditions. Take into account both typical requests and memory-intensive endpoints. Divide the respective sum by the number of workers under consideration and derive a conservative estimate based on multiple observations.
The following calculation is an illustrative example; it is not a measurement. The values used are intended solely to demonstrate the calculation process; they are not a recommendation for a specific application. The result is rounded down to the nearest whole number of workers.
| Calculation step | Acceptance | Classification |
|---|---|---|
| Effective RAM Limit | 4,096 MiB | Host or Container Boundary in the Example |
| Other Services, Pools, and Reserves | 2,048 MiB | Jointly Agreed Deduction |
| Budget for the pool in question | 2,048 MiB | 4,096 minus 2,048 MiB |
| PSS Approximate Value per Worker | 80 MiB | Assumed conservative planning value |
| Calculated RAM Limit | 25 workers | 2,048 divided by 80, rounded down |
The 25 workers do not guarantee a safe allocation. PSS allocates shared pages proportionally, and this allocation changes based on the number of processes sharing those pages. A different request mix can also affect private memory requirements; therefore, the projection should be verified against the observed total consumption and the existing limit.
If shared memory such as OPcache is already included proportionally in the PSS total used, do not deduct it again as a lump sum for the entire amount. Nevertheless, be sure to allow for a reserve to account for memory usage that your analysis does not capture. Especially with a container limit, what ultimately counts is the total consumption of all processes within that limit—not just the estimated total worker count.
A newly started worker alone is not very meaningful as a basis: It may not have processed any demanding requests yet. Therefore, compare multiple time points and note which endpoints and how many workers were involved in each case. This will help you determine whether the chosen approximation holds true even under less favorable but realistic operating conditions.
Estimate the number of workers needed based on requests
The RAM calculation estimates how many workers can likely be accommodated. In contrast, actual demand is determined by how many PHP requests actually arrive in the pool in question and how long they keep a worker occupied. As a first approximation, the average number of workers occupied simultaneously equals the number of PHP requests per second multiplied by the average worker occupancy time in seconds.
Illustrative calculation example, not a measurement: Assuming 20 PHP requests per second and an average processing time of 0.25 seconds, an average of five workers are busy. This is an average over the period under consideration. It does not imply that exactly five processes are always running, nor that five is sufficient as a pool limit for brief spikes.
When calculating the number of requests, do not include all page views without verification. If a cache returns many responses without calling PHP, these hits do not put a strain on the pool. Conversely, cache misses, logged-in visitors, and administrative accesses can sometimes trigger more PHP processing than a daily average would suggest.
The Worker Time Recorded also includes wait times during processing, such as when waiting for a database or an external service. It is not automatically equivalent to the response time visible in the browser. According to fastcgi_finish_request() PHP may have already finished sending the response to the client but still be performing additional work in the worker.
To ensure acceptable wait times, you need some headroom above the average utilization. How much headroom is needed depends, among other things, on load fluctuations, slow endpoints, and the desired response time target. Multiplying the peak requests per second by a high latency percentile can serve as a conservative scenario check, but it is not a precise queueing forecast.
Therefore, consider several time periods separately: A brief peak in activity and quiet nighttime traffic can result in the same daily average as more consistent operations, but they place different demands on the system. If the occupancy time increases due to a slow backend, the average number of tied-up workers also increases even if the arrival rate remains the same. The demand is therefore not solely a function of visitor volume.
Derive pool settings from the plan
Now compare the RAM-based upper limit with the estimated requirement, including a margin. If the requirement falls below that limit, choose a conservative starting value for pm.max_children, which does not have to use up the entire budget. In the example given, 25 would be the calculated RAM limit, but not necessarily the appropriate setting; the CPU and backend may impose limits even before that.
If the estimated demand exceeds the RAM limit, setting a higher limit will not resolve the issue: it may put the host or container under memory pressure. Conversely, a very low limit can cause requests to be queued. In this case, try optimizing execution time or cache usage, and check whether additional resources or a limit on incoming load are necessary.
At dynamic In addition to the upper limit, you specify the initial number as well as the minimum and maximum number of available workers. The initial and reserve values should match the expected load and remain within the upper limit. If too little capacity is reserved, a sudden increase in load may result in the need for additional workers; conversely, having too many idle processes over time consumes resources.
At ondemand Workers are created only when needed; the idle time until they are terminated is configured separately. This can be useful for pools that are rarely used, but requires special attention when there are rapid spikes in load. Here, too, it limits pm.max_children the number of workers in the pool that are available at the same time.
Multiple websites on the same host do not each receive all available RAM independently of one another. Allocate their potential pool limits together with the other services and the reserve. A global FPM process limit, if configured, may also apply, but it does not replace the individual pool budgets or the assessment of CPU and database capacity.
After making changes, check the actual load and wait times over appropriate time periods, rather than treating the initial value as final. With managed hosting, process data or pool settings may not be directly accessible; in that case, use the provider’s metrics and available options. The settings available also depend on the PHP version and operating environment.
Monitor FPM Status and Storage
The FPM status page shows whether the planned workers are sufficient under actual load. Protect the status endpoint Protected from public access: It may disclose sensitive information about requests and resources. A separately configured status listener can remain accessible even when the main pool is overloaded; check its availability and setup for your PHP version and web server configuration.
| Status value | Classification | Follow-up question |
|---|---|---|
| active processes / idle processes | Current Employees and Freelancers | Will there still be available workers during peak loads? |
| listen queue / max listen queue | Current and all-time maximum queue length | Does the queue grow when responses are slow? |
| max children reached | Counter for when the worker limit is reached in "dynamic" or "ondemand" mode | Does the counter increase during the period under consideration? |
| slow requests | Counter for Slow Requests | Does this increase coincide with longer response times? |
Consider the values as time series along with request volume and response times. A past peak value for the queue does not indicate current overload; similarly, for counters, the increase since the last observation is more meaningful than the total value alone. Take into account pool starts or restarts, which can change the reference period.
For a known FPM worker, you can read aggregated memory values on a Linux system with an available proc interface. Replace PID by the actual process ID; you need the appropriate access rights. Repeat the observation for multiple workers and load conditions, rather than deriving a permanent pool size from a single process.
Investigating Slow Requests and Queues
A store may show many active workers, even though PHP execution itself is not the original bottleneck. If requests are waiting for slow database queries, the workers remain tied up in the meantime. If additional requests arrive, the listener queue can grow and response times can increase, even if the CPU still has spare capacity.
A higher worker limit might allow more requests to reach the database simultaneously in this situation. This can Back-end Printing and further increase wait times. Therefore, compare the trends in FPM utilization and queue length with database load, slow queries, and external service calls before you increase the limit.
The FPM slowlog helps pinpoint long PHP calls: For requests exceeding a configured threshold, FPM can log a backtrace. This shows a single execution point and is not a complete profile of the entire request. Recurring points can be cross-referenced with request duration and backend metrics; the Guide to Analyzing the PHP-FPM Slowlog explains the further analysis.
A timeout must also be distinguished from the actual capacity. In nginx, this is referred to as fastcgi_read_timeout the allowed interval between consecutive read operations from the FastCGI server, not the total request duration as a whole. A higher value may allow for longer wait times, but it neither creates additional workers nor speeds up the database.
Capacity Limits and Next Steps
If the RAM budget is insufficient to meet the estimated requirements, a higher setting for pm.max_children Don't overlook the trade-off: Additional processes also require memory. Instead, check whether you can reduce the number of PHP requests or the duration of their worker usage. Which approach makes sense depends on where the observed load is originating.
A more effectively utilized cache can handle repeated requests, while faster PHP execution and database accesses free up workers sooner. Appropriate background tasks can be offloaded from the immediate request path; however, these tasks also require their own resources. A load limit protects the backend during peak times but can result in requests being queued or rejected.
Additional RAM can allow for a higher number of workers if memory is indeed the limiting factor. If the CPU, database, or an external service is already at full capacity, their capacity must also be taken into account. Therefore, more memory alone does not guarantee shorter response times or higher throughput.
If the memory requirements of individual workers exceed their lifetime, then pm.max_requests Arrange for them to be replaced regularly. This can help when dealing with memory leaks in third-party libraries, but it does not address the root cause. After making a change, continue to monitor pool memory and request behavior, rather than treating the restart mechanism as a substitute for debugging.
For a broader architectural decision, the Comparison of NGINX Unit and PHP-FPM Context: NGINX Unit has been archived and is no longer maintained. Regardless of the architecture you choose, you should make changes based on time series Check: For similar request volumes, compare the queue, worker utilization, memory usage, and response times. This will help you determine whether an adjustment has actually resolved the bottleneck or merely shifted it elsewhere.
Sources and Current State of Knowledge
Status of the research:
Research status: November 4, 2026. Check the availability of status listeners, process data, and pool settings for the PHP and Linux versions in use, as well as the hosting environment.
https://www.php.net/install.fpm.configuration
https://www.php.net/fpm.status.php
https://docs.kernel.org/7.0/filesystems/proc.html
https://www.kernel.org/doc/html/v6.12/filesystems/proc.html
https://www.php.net/manual/de/install.fpm.php
https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html



