A PHP worker is a server process that runs PHP code for a request. On a typical WordPress stack, the web server can return a cached page without involving PHP. A cache miss, checkout action, account page, search, form submission, or admin request must wait for an available PHP worker.
The right worker count is not a universal number. It depends on uncached request concurrency, how long each request occupies a worker, available memory, CPU capacity, and database performance. Adding workers helps only while the server has enough resources to run them. Beyond that point, more workers can increase contention and make responses slower.
This 2026 guide replaces generic worker-limit advice with a measurement-first process. It shows what to observe, how to estimate a starting value, how to diagnose saturation, and when optimization is better than another worker. If you are comparing PHP’s process model with an event-driven application stack, start with xCloud’s Node.js hosting overview.
PHP worker problems at a glance
| What you observe | Likely interpretation | Best next check |
|---|---|---|
| Max-children warnings and rising request latency | All configured PHP-FPM children are busy | PHP-FPM status, error log, and uncached concurrency |
| High worker utilization but spare CPU and memory | The pool may be too small | Increase gradually, then repeat the same load test |
| High CPU with a long run queue | The server is compute-constrained | Find slow PHP requests before adding workers |
| Memory pressure, swapping, or OOM kills | The pool can consume more RAM than the server can safely provide | Measure real per-process memory and lower the limit |
| 502 errors | PHP-FPM may be unavailable, restarting, or failing upstream | Web-server and PHP-FPM logs |
| 504 errors | An upstream request exceeded its timeout | Slow log, database queries, external calls, and queue time |
| Fast cached pages but slow checkout or account pages | Dynamic requests are the bottleneck | Test uncached routes separately |
| Many scheduled tasks during traffic peaks | User requests and background work may compete | Move heavy jobs to controlled queues or off-peak schedules |
What is a PHP worker?
A PHP worker is one PHP-FPM child process that can execute one PHP request at a time. PHP-FPM manages a pool of these processes and assigns incoming FastCGI requests to available children.
A simplified WordPress request looks like this:
-
The browser sends a request to the web server.
-
A full-page cache answers immediately when it has a valid copy.
-
On a cache miss, the web server passes the request to PHP-FPM.
-
An available PHP worker loads WordPress, runs plugins and theme code, queries the database, and builds the response.
-
If every worker is occupied, the request waits or eventually times out.
The official PHP-FPM configuration reference calls the main capacity setting pm.max_children. It defines the limit on simultaneous requests served by a pool. The process manager can run in static,dynamic, or ondemand mode, but none of those modes creates free CPU or memory.
A worker is not the same thing as a visitor. One visitor may make several PHP requests, while thousands of visitors may receive cached pages without touching PHP. Size the pool from simultaneous dynamic work, not monthly visits or page-view totals.
PHP workers, queue workers, and persistent worker mode are different
The word “worker” is overloaded. Separate these three concepts before changing a setting:
| Worker type | What it does | Typical control |
|---|---|---|
| PHP-FPM request worker | Runs one web request at a time | pm.max_children or a hosting control |
| Application queue worker | Processes background jobs such as emails or imports | Queue manager, Supervisor, systemd, or a platform service |
| Persistent application worker | Keeps an application bootstrapped between requests | Runtime-specific configuration, such as FrankenPHP worker mode |
A WordPress cron event may execute inside a web request or through a CLI process, depending on the site’s setup. That does not make every PHP-FPM child a dedicated background worker. Similarly,FrankenPHP worker mode keeps an application in memory across requests, which changes the lifecycle and deployment considerations. Do not apply PHP-FPM sizing rules blindly to a persistent runtime.
Why PHP worker capacity matters
Worker capacity affects uncached throughput and queue time. It matters most on sites with a high proportion of dynamic requests, including:
- WooCommerce checkout, cart, account, and API routes
- membership and learning-management systems
- logged-in dashboards and WordPress administration
- search, filtering, and form submissions
- uncached REST API traffic
- imports, exports, scheduled events, and webhook handlers
Caching can remove many public page views from PHP, but it cannot safely turn every personalized or transactional route into a static response. That is why two sites with similar traffic can need very different worker pools.
Worker count is also only one limit in a chain. A PHP worker can be available while the database, Redis, an external payment API, storage, or CPU remains saturated. Treat the whole request path as a system.
How many PHP workers do you need?
Estimate PHP workers from peak uncached request rate multiplied by average request duration, then validate the estimate under a representative load test. This is a starting point, not a guarantee.
For a stable workload:
estimated busy workers = uncached requests per second × average PHP request time in seconds
If the site receives 12 uncached requests per second and the average PHP request occupies a worker for 0.4 seconds, the average concurrency is about 4.8 workers. Starting with five would leave no margin for bursts or slow-tail requests, so test a modestly higher value while watching CPU, memory, queueing, and high-percentile latency.
Do not calculate from the cached homepage alone. Test the routes that actually invoke PHP. For a store, include product filtering, cart updates, checkout, account pages, and webhooks. For a membership site, include logged-in navigation and searches.
Account for memory before increasing the pool
Each PHP process consumes memory, and consumption varies with WordPress, plugins, request type, and runtime state. Measure several workers under representative traffic rather than copying a fixed MB-per-worker number.
A conservative capacity check is:
safe worker ceiling = RAM budget for PHP ÷ measured high-end memory per worker
Keep memory for the operating system, web server, database, cache, monitoring agents, and traffic spikes. If increasing pm.max_children causes swapping or out-of-memory kills, the new number is not useful capacity.
Account for CPU and downstream limits
Workers that are actively executing PHP need CPU time. More runnable processes than the server can efficiently schedule may increase context switching and latency. Database connections and external services can become the next bottleneck as concurrency rises.
Increase the pool in small steps and repeat the same test. Stop when throughput no longer improves, latency worsens, errors rise, or a resource reaches its safe operating range.
A repeatable sizing workflow
1. Establish an uncached baseline
Choose representative dynamic routes and record:
- requests per second
- median and high-percentile response time
- error rate
- PHP-FPM active, idle, and total processes
- whether the pool reached its maximum children
- CPU utilization and run queue
- available memory, swap activity, and OOM events
- database latency and connection pressure
The PHP-FPM status page can expose accepted connections, listen queue, active processes, idle processes, maximum active processes, and whether the pool reached pm.max_children. Protect this endpoint. It should never be publicly accessible.
2. Run controlled, representative load
Test dynamic routes with realistic sessions, cache state, and think time. A benchmark that repeatedly hits one cached URL does not measure PHP worker demand. Keep the test input constant so a worker-count change is the main variable.
Begin below expected peak load, then increase gradually. Stop if error rates or resource pressure become unsafe. Production traffic is not the place to discover that a test script has no upper bound.
3. Change one variable
Increase the worker limit in a small step. Repeat the same test and compare:
- Did successful dynamic throughput increase?
- Did queue time and high-percentile latency fall?
- Did CPU or memory pressure increase?
- Did database or upstream latency become the new limit?
If the answer is “more resource use, no useful throughput gain,” revert and optimize the slow path.
4. Recheck after application changes
Plugin updates, a new checkout extension, a larger catalog, PHP version changes, and traffic-mix shifts can alter request duration and memory use. A worker number is a current operating decision, not a permanent property of the site.
For a broader server-readiness review, use the PHP hosting setup checklist. Teams deciding between framework conventions can also compare Node.js and Laravel and read the Laravel beginner’s guide before choosing a runtime around one concurrency setting.
How to diagnose PHP worker saturation
Saturation means demand is reaching the pool’s ability to start work immediately. The strongest signal is not “the site feels slow.” It is several measurements moving together: workers at the configured maximum, a non-zero listen queue, max-children warnings, and worsening latency on dynamic routes.
Check PHP-FPM status and logs
Use the status page or platform metrics to inspect active and idle processes. Search the PHP-FPM log for messages indicating that the pool reached pm.max_children. A single occurrence during a deployment may be less important than a sustained pattern during normal peaks.
Enable the PHP-FPM slow log with care in an appropriate environment.request_slowlog_timeout can trigger a backtrace for slow requests, while slowlog sets the destination. The PHP manual documents both settings. Protect logs because request context can contain sensitive data.
Distinguish 502 from 504 symptoms
A 502 Bad Gateway often means the web server could not get a valid response from PHP-FPM, for example because the upstream process was unavailable, crashed, or restarted. A 504 Gateway Timeout means the upstream did not respond within the configured time.
Neither status proves that the worker count is too low. Correlate the timestamp with web-server logs, PHP-FPM logs, system memory events, deployment activity, and database metrics before changing capacity.
Find slow requests, not only busy workers
A pool can saturate because demand rose, because each request became slower, or both. One plugin update or external API timeout can occupy workers much longer without increasing visitor traffic.
Profile the slow route. Check database query time, remote HTTP calls, filesystem access, lock contention, and application logs. Reducing average request time from 800 ms to 400 ms can approximately double the throughput of the same worker pool for that route, subject to other bottlenecks.
When to add workers and when to optimize
| Situation | Add workers? | Better action |
|---|---|---|
| Pool is full; CPU and memory have safe headroom | Test a small increase | Validate with the same dynamic workload |
| Pool is full; CPU is already saturated | Usually no | Profile expensive PHP paths and database work |
| Pool is full; memory pressure or swapping is present | No | Reduce process memory, lower the pool, or add resources |
| Public pages generate avoidable PHP traffic | Not first | Add page caching and verify exclusions |
| A remote API holds requests open | Not first | Add timeouts, retries with limits, queues, or asynchronous handling |
| Cron, imports, and emails compete with checkout | Not first | Move or schedule background work deliberately |
| A predictable campaign creates a short peak | Maybe | Load-test capacity, warm caches, and plan scale before launch |
The important distinction is capacity versus efficiency. Adding a worker increases potential concurrency. It does not shorten the code path, speed up a query, or make an external API respond faster.
Use caching without hiding dynamic failures
Full-page caching reduces PHP demand for anonymous, cacheable pages. Object caching can reduce repeated database work. Both should be monitored for hit ratio and correctness.
Never use a cached-homepage score as proof that checkout is healthy. Exclude personalized and transactional routes correctly, then measure them separately.
Move background work out of the request path
A user should not wait for a large export, image batch, or non-critical email campaign to finish. Queue long tasks and bound the number of queue workers so they cannot consume every CPU core or database connection needed by web traffic.
Background processing still uses server resources. Moving work to a queue improves control and user response time; it does not make the work free.
How to adjust PHP workers in xCloud
xCloud lets a site owner control the maximum PHP workers for a site rather than tying the number to an arbitrary per-plan cap. The safe number is still limited by the server’s CPU, memory, and workload.
-
Open the site in the xCloud dashboard.
-
Select Site Settings.
-
Open PHP Settings.
-
Change Max PHP Workers.
-
Save the setting.
-
Repeat the same dynamic load check and compare the results.
Do not change the value during an unexplained incident and assume the issue is solved. Capture the before-and-after metrics, watch for resource pressure, and revert if latency or errors worsen.
Deploying application changes through a repeatable workflow makes these comparisons easier. See xCloud’s one-click Git deployment guide for the repository-to-server path.
Common PHP worker mistakes
Treating visits as concurrent PHP requests
Monthly visitors are not a sizing input. Cached requests may bypass PHP, and one active user can generate several dynamic requests. Measure peak uncached concurrency.
Copying another host’s worker number
Providers may use different CPUs, process-manager settings, memory limits, caches, and definitions. “Four workers” is not a portable performance result.
Setting a high maximum because it is allowed
An unrestricted control is not an unlimited resource. A high pm.max_children value can permit enough simultaneous processes to exhaust RAM or overload CPU and the database.
Ignoring slow-tail latency
An acceptable average can hide a slow checkout tail. Track high-percentile response time and errors for the routes that affect users and revenue.
Confusing PHP-FPM workers with threads
A PHP-FPM child is an operating-system process. Search results for php worker also include the old pthreads-style Worker class and parallel programming. Those are separate topics from sizing a web-serving PHP-FPM pool.
PHP worker checklist
Before raising a limit, confirm that you can answer these questions:
- Which uncached routes are slow or queued?
- What are the peak uncached requests per second and request duration?
- Does PHP-FPM reach
pm.max_children? - Is the listen queue growing?
- How much memory do workers use under representative load?
- Does the server have CPU and memory headroom?
- Are database queries or external services the real bottleneck?
- Are scheduled and queue jobs competing with user traffic?
- Did the same load test improve after the change?
- Is the status endpoint protected from public access?
If any answer is unknown, gather the measurement before buying capacity or raising the pool.
Frequently asked questions
What does a PHP worker do?
A PHP worker runs PHP code for one request at a time. With PHP-FPM, the process manager maintains a pool of child processes. Cached pages may bypass the pool, while uncached WordPress pages, account actions, checkout, forms, and admin requests generally need a worker.
How many PHP workers do I need for WordPress?
There is no universal count. Estimate from peak uncached request rate and request duration, verify memory and CPU headroom, then load-test dynamic routes. A brochure site with effective caching can need fewer workers than a lower-traffic store with personalized pages and slow plugins.
Do more PHP workers make WordPress faster?
More workers can reduce queueing when all existing workers are busy and the server has spare resources. They do not make one request execute faster. If CPU, memory, the database, or an external service is saturated, adding workers can make performance worse.
What is pm.max_children?
pm.max_children is the PHP-FPM pool limit on child processes that can serve simultaneous requests. Its safe value depends on process memory, CPU capacity, other services on the server, and the workload. It should be tested rather than copied from a generic recommendation.
Can caching reduce PHP worker demand?
Yes. A valid full-page cache can answer many anonymous requests without running WordPress PHP. Object caching can shorten some dynamic requests. Checkout, account, admin, API, and other personalized traffic still require careful measurement.
Is a 504 error always caused by too few PHP workers?
No. A 504 means an upstream response exceeded a timeout. Worker queueing can contribute, but slow database queries, external API calls, locks, overloaded CPU, and application bugs can produce the same symptom. Correlate logs and metrics before changing the pool.
Final recommendation
Treat PHP workers as a finite concurrency budget. Start with real uncached request data, measure process memory and CPU headroom, adjust in small steps, and compare the same workload after every change.
The goal is not the highest worker number. It is the smallest reliable pool that serves peak dynamic demand without excessive queueing, memory pressure, or CPU contention. Optimize slow requests and background work before assuming another worker is the answer.
If you have found this blog helpful, feel free to subscribe to our blogs for tutorials, guides, and practical server-management advice.
Last updated September 22, 2026
← All articles