Context
A busy PHP site reports that it has reached its maximum child processes. Increasing pm.max_children looks like an obvious fix, but a larger pool can exhaust memory or overload the database. The useful setting is the amount of concurrency the whole service can support. That requires measurements from representative requests and a budget covering every process sharing the server.
Understand the control
The PHP-FPM manual documents pm.max_children as the limit on child processes and therefore simultaneous requests served by a pool. Process-manager mode changes how workers are maintained, with related settings for dynamic and on-demand operation. Review the effective pool configuration for the installed PHP version before changing a value.
A worker limit is not the same as the web server's connection capacity. Clients can wait upstream while every PHP worker is busy. The incident may involve slow requests, insufficient useful concurrency, or a dependency that becomes slower when more requests run together. Identify which situation the evidence supports.
An illustrative overloaded database
Imagine a listing site whose requests spend most of their time waiting for expensive database queries. The FPM queue grows. Doubling workers sends more simultaneous queries to the same database, increasing contention and keeping each worker occupied longer.
Measure request duration, database time, pool queue behaviour, CPU, memory pressure, and completed requests over the same interval. A bigger worker count is successful only if useful throughput and latency improve without creating a new capacity failure.
Measure representative worker memory
Observe workers after realistic request paths have run, including administrative actions and memory-heavy endpoints. A newly started idle process may consume less memory than one handling image processing or a large report. Do not size production solely from a single idle snapshot.
Understand the memory metric used. Summing resident memory can count shared pages more than once, while proportional measurements can help attribute shared memory where available. Whichever method you use, document it and compare the resulting budget with actual server behaviour under load.
Budget the complete host
Reserve capacity for the operating system, web server, database if local, caches, agents, scheduled jobs, and deployment overlap. Include other FPM pools and PHP versions. A per-pool calculation can look safe while the sum across all pools exceeds the machine's practical capacity.
Leave headroom for workload variation and recovery. A server that runs at the edge of memory during normal traffic has little room for a backup, import, or burst. The budget should state assumptions and measured ranges rather than presenting one average worker size as a permanent constant.
Find requests holding workers
Use FPM status and slow-request evidence through appropriately restricted endpoints and logs. Correlate slow stacks with application request identifiers. A pool can be full because workers are waiting on a remote API or serialised session access, not because PHP computation requires more CPU.
Review application changes that introduced slow work into synchronous requests. Exports, image transformations, and background maintenance may belong in bounded job processing. Moving them requires application design, but it can improve web capacity more sustainably than increasing every server limit.
Tune one dimension at a time
Choose a candidate pool size consistent with the memory and dependency budget. Test the request mix at increasing concurrency and observe completed work, latency, queueing, database pressure, and memory. Keep the baseline configuration and test conditions.
Review process-manager behaviour separately. Startup and spare-worker settings affect how quickly capacity becomes available, while recycling settings can influence memory growth and churn. Do not change every parameter together and then attribute improvement to max_children alone.
Test saturation and recovery
Drive the service to a controlled saturation point in a representative environment. Confirm it queues, rejects, or slows requests in a documented way rather than triggering widespread out-of-memory termination. Then reduce load and verify normal latency returns.
Include a slow dependency scenario. The site should expose the failed boundary and recover when it clears. An unbounded queue can make a short upstream interruption produce a much longer customer incident after the dependency has already recovered.
Quick diagnostic map
| Evidence | Interpretation | Next check |
|---|---|---|
| Pool full; CPU is low | Workers wait elsewhere | Inspect slow request stacks |
| More workers worsen latency | Dependency capacity exceeded | Measure useful throughput |
| Memory pressure follows burst | Whole-host budget exceeded | Review all pools |
A focused operator exercise
Select a representative request mix including a database-heavy page, a memory-heavy operation, and ordinary cached and uncached traffic. Record the effective pool configuration and all other services sharing the host. Measure worker memory after real work, explaining the chosen memory metric and shared-page treatment before calculating a candidate concurrency budget.
Run a controlled concurrency sweep with the current pool, then one proposed setting. Compare completed requests, latency, queueing, CPU, database waits, and memory pressure. Keep the dataset and request mix constant. A higher worker count should be accepted only when useful throughput improves within the whole-host and dependency budget.
Introduce a slow test dependency and verify saturation and recovery behaviour. Inspect whether queued requests remain bounded and normal latency returns when the fault clears. The receipt should identify the measured operating envelope, headroom, and next scaling trigger. This is stronger evidence than a formula based on total RAM and one newly started worker's resident memory.
Record the operating envelope
Keep the pool configuration, measured worker range, total host budget, request mix, and observed throughput together. Monitor queue length, busy workers, slow requests, memory pressure, and application latency after deployment.
Clouvenix can help size FPM in the context of the web server, database, and application. The outcome is a documented concurrency envelope supported by measurements and a clear next action when the workload outgrows it.
Frequently asked questions
Can I divide total RAM by one worker's RSS?
That is too crude as a complete sizing method. Account for shared memory, representative peak behaviour, other services, other pools, and headroom, then validate the candidate under realistic concurrency.
Does a max_children warning always mean the pool is too small?
It means the configured concurrency boundary was reached. Slow queries, remote calls, session contention, or excessive synchronous work may be holding workers. Diagnose those causes before assuming more processes will improve the service.
Explore Clouvenix server performance for implementation and operational handover.