PHP-FPM performance is mainly about matching worker behavior to your workload and available memory—not choosing one “fastest” mode from a generic tutorial.
PHP-FPM supports three process-manager modes:
- static — keeps a fixed number of child processes.
- dynamic — adjusts child processes between configured spare-server limits.
- ondemand — starts workers when requests arrive.
The correct choice depends on:
- Traffic pattern.
- Available RAM.
- Average worker memory.
- Concurrency.
- Request duration.
- Cache state.
- Whether idle-memory efficiency or immediate warm capacity matters more.
This guide uses the official PHP-FPM configuration model as the baseline. It explains how to design a valid benchmark but does not invent performance results.
Any future Digital Bhatti benchmark should publish the complete environment, request type, concurrency, cache state, run count, memory measurements and statistical summary before making performance claims.
Last verified: September 24, 2026. PHP-FPM directives and support windows can change; verify the effective pool configuration and the current supported-version table before standardizing production systems.
The existing URL contains benchmark, but this page is intentionally a documentation-based tuning guide unless reproducible measured results are added. Keep the existing permalink to avoid an unnecessary migration.
Size PHP-FPM From Memory and Workload, Not From CPU Count Alone
The worker limit controls simultaneous PHP requests. Each process consumes memory, so an oversized pool can cause swapping or OOM conditions while an undersized pool can create queueing.
1. What Is PHP-FPM?
PHP-FPM is PHP's FastCGI Process Manager. See the official PHP-FPM documentation for the current feature and security model.
It manages pools of PHP worker processes that receive requests from a web server such as Nginx or Apache using FastCGI.
listen.allowed_clients and upstream firewall controls. For host-level exposure controls, see the Linux VPS Security Hardening Guide.
PHP's official documentation highlights features including:
- Multiple worker pools.
- Static, dynamic and ondemand process spawning.
- Slow request logging.
- Status information.
- Different users/groups and configuration per pool.
- Graceful process management.
2. static vs dynamic vs ondemand
| Mode | Worker Behavior | Potential Advantage | Main Trade-off |
|---|---|---|---|
| static | Keeps exactly pm.max_children workers. |
Predictable warm capacity. | Idle workers still consume memory. |
| dynamic | Starts with configured workers and adjusts between spare limits. | Balances readiness and memory use. | Requires more tuning parameters. |
| ondemand | Spawns workers when requests arrive. | Lower idle-memory footprint. | New worker creation can add latency after idle periods. |
3. How static Works
With pm = static, PHP-FPM keeps a fixed number of children equal to pm.max_children.
pm = static
pm.max_children = 12
This means 12 PHP workers remain available regardless of whether traffic is high or idle.
Static can make sense when:
- Traffic is steady.
- Memory is well understood.
- Warm worker availability matters.
- The server is dedicated primarily to the PHP workload.
It can be wasteful when the site is idle for long periods and RAM is scarce.
4. How dynamic Works
With pm = dynamic, PHP-FPM adjusts the number of workers using the parameters defined in the official FPM configuration reference:
pm.max_childrenpm.start_serverspm.min_spare_serverspm.max_spare_servers
pm = dynamic
pm.max_children = 16
pm.start_servers = 4
pm.min_spare_servers = 4
pm.max_spare_servers = 8
Dynamic is often a sensible starting point for general-purpose servers because it maintains some idle capacity while allowing the pool to expand.
That does not mean these example values should be copied blindly.
Current PHP-FPM also exposes pm.max_spawn_rate for dynamic mode, limiting how quickly the pool can create children as it grows. The documented default is 32. Leave advanced spawn-rate tuning alone unless measured burst behavior shows a reason to change it.
5. How ondemand Works
With pm = ondemand, PHP-FPM creates children when requests arrive.
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 10s
Idle processes can be terminated after the configured timeout. The documented default for pm.process_idle_timeout is 10 seconds and it applies only to ondemand.
This can reduce idle-memory usage on low-traffic servers or servers hosting many quiet pools.
The trade-off is that a request arriving after workers have exited may need to wait for a new worker to spawn.
6. There Is No Universal Best PHP-FPM Mode
Avoid rules such as:
- “static is always fastest.”
- “dynamic is always best for WordPress.”
- “ondemand is always best on low-RAM VPS.”
Each statement ignores workload shape.
The correct choice depends on measured:
- Worker memory.
- Peak concurrency.
- Request duration.
- Idle periods.
- Queueing.
- System-wide memory pressure.
7. Understanding pm.max_children
pm.max_children limits the number of simultaneous PHP requests a pool can serve.
If all children are busy, additional PHP requests can wait in the FastCGI listen queue until a worker becomes available, subject to the listener/backlog and web-server behavior.
That queueing can increase backend response time. Do not assume every queue event means pm.max_children should be raised; slow application requests or a saturated database can keep workers occupied and create the same symptom.
For broader diagnosis of initial-response latency, use our TTFB Optimization Guide.
8. Do Not Size pm.max_children From CPU Count Alone
A common formula such as:
pm.max_children = CPU cores × fixed multiplier
is incomplete because PHP workers consume memory and workloads vary dramatically.
A more useful starting point is memory-aware sizing.
9. Measure Real PHP Worker Memory
Do not assume every PHP-FPM child uses 20 MB, 50 MB or 100 MB.
Measure your actual application under realistic load.
Start by identifying the actual FPM master/worker process names on the host:
ps -eo pid,ppid,rss,comm,args | grep '[p]hp-fpm'
Then measure worker memory under representative uncached/dynamic load rather than immediately after startup. Distribution package names can look like php-fpm, php8.4-fpm, php8.5-fpm or something else, so do not assume one process name.
RSS can be useful for rough capacity planning but counts shared pages in each process and therefore can overstate truly unique memory. Where available, compare it with proportional-set-size (PSS) data from tooling such as smem. Use a representative range or high-percentile worker footprint rather than trusting one idle snapshot or one average.
10. A Safer Memory-Sizing Formula
A practical starting estimate is:
Usable RAM for PHP
=
Total RAM
-
OS / Web Server / Database / Cache / Other Services / Safety Margin
Estimated max_children
=
Usable RAM for PHP
÷
Observed PHP Worker Memory
This is a memory ceiling estimate, not a final configuration target. Reserve headroom for the kernel, web server, database, Redis/object cache, OPcache shared memory, monitoring agents, backup jobs and temporary spikes. Avoid planning around swap as normal PHP capacity.
The safe production value may need to be substantially lower because CPU saturation, database capacity, storage I/O, request duration, external API latency and real concurrency can become limiting before RAM is exhausted.
11. Example Sizing Calculation
Suppose a server has the following illustrative measurements:
- 8 GB RAM total.
- 4 GB reserved for OS, database, cache, web server and safety margin.
- Measured PHP workers averaging about 100 MB RSS.
A rough memory ceiling would be:
4096 MB
÷
100 MB per worker
≈
40 workers
That does not mean you should immediately configure 40 workers.
The CPU, database, storage or another downstream service may saturate long before memory does. Treat the calculated worker count as an upper bound to test against, not a recommended value.
12. Watch for Worker Saturation
Signs that the pool may be too small include:
- Requests queue during traffic bursts.
- Logs report that
pm.max_childrenhas been reached. - TTFB rises sharply under concurrency.
- CPU still has available headroom while PHP requests wait.
Do not increase worker count if the real bottleneck is already CPU, database or I/O saturation.
13. Diagnose Queueing Before Increasing Workers
When latency rises under load, first determine whether PHP-FPM is actually queueing requests. The FPM status interface can expose listen queue, max listen queue, listen queue len, active/idle/total processes, max active processes, max children reached, slow-request count and memory peak.
Useful signals include:
- listen queue > 0: requests are waiting for an available worker.
- max children reached > 0: the pool has hit its configured concurrency ceiling at least once since the pool started; it does not by itself tell you that raising the limit is safe.
- high active / low idle workers: the pool is near saturation.
- low queue but high CPU or database latency: adding workers may not solve the real bottleneck.
Use FPM status only on a trusted administrative or monitoring path. Do not expose process/status details publicly.
14. Use pm.status_path and pm.status_listen Deliberately
pm.status_path defines the URI used for the FPM status page. PHP warns that this endpoint can expose request URLs and resource information, so it should be restricted to internal requests or known monitoring clients.
For difficult saturation incidents, PHP-FPM also provides pm.status_listen. This creates a separate invisible pool for status requests, allowing monitoring to remain reachable even when the main application pool is occupied by long-running requests.
That separation can make diagnosis more reliable, but the status listener is still administrative infrastructure. Keep it private and configure the web server/monitoring path carefully.
15. Watch for Too Many Workers
Oversizing can cause:
- Memory exhaustion.
- Swap activity.
- OOM kills.
- Database overload.
- CPU contention.
- Higher latency despite more workers.
More concurrency is useful only while downstream resources can handle it.
If PHP-FPM exhaustion or slow upstream execution progresses into gateway failures, use the Nginx 502/504 Troubleshooting Guide to separate pool saturation from upstream timeouts, crashes or socket failures.
16. pm.max_requests Is a Worker-Lifecycle Control
pm.max_requests controls how many requests a child process handles before it is respawned. The documented default is 0, which means a worker can process requests indefinitely.
Non-zero values can help limit long-term memory growth caused by third-party libraries or application behavior, but recycling also creates process churn. Do not choose a low value simply because a tuning checklist says “restart workers often.”
Use memory trends and operational evidence to justify the setting, and fix genuine leaks where possible instead of relying on aggressive recycling as the primary solution.
17. PHP-FPM Slowlog
PHP-FPM supports slow-request tracing. The official FPM documentation describes slowlog support as a way to record backtraces for unusually slow scripts.
A typical configuration can include:
request_slowlog_timeout = 3s
slowlog = /var/log/php-fpm/www-slow.log
Use a threshold appropriate to the workload.
The slowlog is valuable because a worker shortage may actually be caused by a few slow requests holding workers for too long.
Keep request_slowlog_timeout separate from request_terminate_timeout. The former records a backtrace after the threshold while allowing the request to continue; the latter can kill the worker serving an overlong request.
The default for both timeout controls is effectively off (0) until configured. A termination timeout should be introduced only after understanding legitimate long-running jobs, uploads, imports, cron/CLI behavior and code that calls fastcgi_finish_request(). PHP also provides request_terminate_timeout_track_finished for cases where the terminate timeout must continue to apply after FastCGI response completion.
18. Status Page and Pool Metrics
PHP-FPM can expose basic and extended status information that helps diagnose pool behavior. Current PHP documentation lists structured output formats including JSON, XML and OpenMetrics, making the status interface usable by monitoring systems without scraping human-oriented text.
Useful status signals include:
- Active processes.
- Idle processes.
- Accepted connections.
- Queueing.
- Maximum active processes.
- Whether the pool reached the configured worker ceiling.
Do not expose the status endpoint publicly without appropriate access controls. Restrict status and ping endpoints to trusted administrative paths or monitoring systems.
19. Validate Configuration Before Reloading PHP-FPM
Before a production reload or restart, test the configuration with the FPM binary provided by your distribution. PHP-FPM supports -t / --test for configuration validation.
# EXAMPLE ONLY — binary/service name varies by distribution
sudo php-fpm8.5 -t
Do not copy the binary name blindly. Debian/Ubuntu, RHEL-family systems, custom packages and source builds can use different names and configuration paths.
After a successful syntax test, prefer the least disruptive supported reload method for the platform, verify the service remains healthy, then check status metrics, error logs, memory and real requests. Keep the previous pool configuration available for rollback.
20. PHP-FPM and WordPress Page Caching
Full-page caching can dramatically reduce the number of requests that reach PHP-FPM.
Cache Hit
↓
Serve Cached Response
↓
PHP-FPM May Be Bypassed
Cache Miss
↓
PHP-FPM Worker
↓
WordPress + Database
↓
Response
Benchmark PHP-FPM modes using the request types you actually care about.
21. WooCommerce Is Different
WooCommerce has more dynamic requests that may bypass full-page caching:
- Cart.
- Checkout.
- Account pages.
- Authenticated sessions.
- Some AJAX/REST requests.
That makes worker capacity and request duration more important than on a mostly cached blog.
For the broader application stack, use the WooCommerce Speed Optimization Guide.
22. PHP-FPM and Redis
Redis object caching can reduce repeated database/application work for suitable WordPress workloads.
It does not eliminate the need for PHP workers.
Object-cache effectiveness depends on:
- Hit rate.
- Query patterns.
- Plugin behavior.
- Cache invalidation.
23. PHP-FPM and OPcache
OPcache reduces repeated PHP script compilation by storing compiled bytecode in shared memory.
It should normally be considered separately from FPM process-manager mode.
A poorly sized FPM pool and a poorly configured OPcache are different problems.
24. static: When It Can Make Sense
Static can be appropriate when:
- Traffic is steady and predictable.
- Worker memory has been measured.
- RAM is sufficient.
- Low idle-memory efficiency is acceptable.
- You want fixed warm capacity.
Its main weakness is that the configured worker memory remains allocated even when traffic is low.
25. dynamic: When It Can Make Sense
Dynamic can be appropriate when:
- Traffic varies.
- You want some warm workers available.
- You want unused capacity to shrink within limits.
- The site has recurring bursts but not constant peak concurrency.
It is often a reasonable default for general-purpose deployments, but it still requires measurement.
26. ondemand: When It Can Make Sense
Ondemand can be appropriate when:
- Traffic is low or intermittent.
- Many quiet pools share a server.
- Idle memory matters.
- Occasional process-spawn latency is acceptable.
Do not assume ondemand automatically performs best on a small VPS. Test the request pattern that matters.
27. How to Benchmark PHP-FPM Modes Properly
This section describes a reproducible test design. It does not report Digital Bhatti benchmark results.
A credible comparison should record:
| Variable | Record |
|---|---|
| PHP version | Exact release |
| OS | Distribution/version |
| Hardware | CPU, RAM, storage |
| Web server | Nginx/Apache/LiteSpeed configuration |
| Application | WordPress/version/theme/plugins/dataset |
| Request type | Cached/uncached/admin/AJAX/checkout/API |
| Concurrency | Exact simultaneous clients |
| FPM config | All relevant pm.* values |
| Runs | Repetitions / warm-up |
| Statistics | Median, p95/p99, throughput, errors, queue depth, memory and CPU |
| Pool warm state | Especially important for ondemand; record whether workers were already alive before each run |
| Downstream state | Database/object-cache health, external APIs and storage I/O during each run |
28. Example Benchmark Commands
For simple HTTP load generation, tools such as wrk, hey or ab can be used carefully.
Example with wrk:
wrk -t4 -c20 -d60s https://example.com/uncached-test-page/
Do not run aggressive load tests against infrastructure you do not own or have explicit permission to test. Prefer staging or an isolated production-like environment for mode comparisons. If production testing is unavoidable, keep concurrency conservative, define a stop condition, monitor error/queue/resource metrics live, and avoid checkout or other state-changing endpoints unless the test environment is specifically designed for them.
29. Metrics to Compare
Do not rank modes from requests/second alone.
Track:
- Median latency.
- p95 or p99 latency.
- Throughput.
- Error rate.
- Queueing.
- CPU utilization.
- RAM usage.
- Swap activity.
- Database load.
- FPM listen queue and max listen queue.
max children reached.- Slow-request count.
30. PHP-FPM and Core Web Vitals
PHP-FPM tuning can influence the initial server response when backend queueing or PHP execution is a limiting factor.
That can indirectly affect LCP when backend response delay is part of the LCP path, especially on uncached HTML responses. It does not guarantee an LCP improvement if the dominant bottleneck is image discovery, CSS, fonts or browser rendering.
It does not directly fix INP or CLS.
For frontend/user-experience diagnosis, use our Core Web Vitals Optimization Guide.
31. Managed WordPress vs Self-Managed PHP-FPM
Many managed WordPress hosts do not expose low-level PHP-FPM process-manager configuration to customers.
That can be a feature rather than a limitation if you do not want to operate the server stack yourself.
If your provider manages PHP-FPM for you, focus on the controls it actually exposes—PHP version, worker/concurrency limits, application caching, database performance and support escalation—rather than trying to apply raw pool directives that the platform does not support.
32. When You Need a VPS
You generally need server-level control to tune PHP-FPM directly.
That may mean:
- A self-managed VPS.
- A managed VPS that exposes PHP-FPM controls.
- A cloud server.
- A dedicated server.
If you are choosing infrastructure specifically to gain FPM-level control, separate that hosting decision from this tuning guide and verify that the provider actually allows pool configuration rather than assuming every VPS/managed plan exposes the same controls.
33. Architecture Context
PHP-FPM access differs by hosting model.
Shared hosting often hides server-level configuration. VPS and cloud environments provide more control but require more operational responsibility.
For the architecture trade-offs, read our Shared vs VPS vs Cloud Hosting Guide.
34. Practical Starting Strategy
Measure worker memory
↓
Observe real concurrency
↓
Check queueing / max_children events
↓
Choose process-manager mode
↓
Set conservative worker limit
↓
Validate FPM configuration
↓
Reload safely + verify health
↓
Load test representative requests
↓
Monitor queue / CPU / RAM / DB / errors
↓
Keep rollback config
↓
Adjust one variable at a time
35. Common PHP-FPM Tuning Mistakes
- Copying another server's configuration.
- Choosing workers from CPU count alone.
- Ignoring PHP worker memory.
- Ignoring database capacity.
- Benchmarking only cached pages.
- Testing one concurrency level.
- Using only average latency instead of tail latency.
- Increasing max_children until the server swaps.
- Claiming one mode is universally fastest.
- Ignoring slow application requests that hold workers open.
- Raising
pm.max_childrenafter seeing a queue without checking CPU/database/I/O saturation. - Using RSS as exact unique per-worker memory without accounting for shared pages.
- Exposing FPM status or FastCGI listeners publicly.
- Setting a low
pm.max_requestswithout evidence and creating unnecessary worker churn. - Editing pool configuration without running a syntax test or keeping rollback access.
36. Final PHP-FPM Decision Framework
Steady traffic + known memory + fixed warm capacity needed
↓
Consider static
Variable traffic + want warm spare workers
↓
Consider dynamic
Low/intermittent traffic + idle memory matters
↓
Consider ondemand
In every case:
Measure → change one variable → syntax-test → reload safely
→ load test → monitor → keep rollback → adjust
The best PHP-FPM configuration is the one that handles your real workload without queueing, memory pressure or downstream saturation.
Object Cache vs PHP-FPM Tuning
Persistent object caching and PHP-FPM tuning solve different backend constraints.
- Redis/Memcached: can reduce repeated database/object work.
- PHP-FPM: controls PHP process availability, worker behavior and request queuing.
If workers are saturated, changing cache backends alone will not solve the queue. If repeated database/object work dominates, worker tuning alone may not remove that cost.
For the cache-backend decision, use our Redis vs Memcached for WordPress guide.
Frequently Asked Questions
What is PHP-FPM?
PHP-FPM is PHP's FastCGI Process Manager. It manages PHP worker processes and supports multiple pools, process-management modes, slow logs and status information.
What are the PHP-FPM process-manager modes?
The official modes are static, dynamic and ondemand.
Is static faster than dynamic?
Not universally. Static keeps workers pre-created, but real performance depends on workload, worker count, CPU, RAM, request duration and downstream resources.
Is ondemand best for low RAM?
It can reduce idle-memory usage, but process creation after idle periods can add latency. Test the actual workload rather than relying on a universal rule.
How do I calculate pm.max_children?
Start with measured PHP worker memory and the RAM actually available to PHP, then validate against CPU, database capacity, concurrency and queueing under representative load.
What happens when pm.max_children is reached?
All available PHP workers are busy, so additional requests can wait in the FastCGI listen queue until capacity becomes available. A non-zero max children reached counter confirms the ceiling was hit at least once, but you should check CPU, database, I/O and slow requests before raising the limit.
What is pm.status_listen?
It creates a separate FPM status listener backed by an invisible pool, allowing status requests to be served even when the main application pool is busy. Keep it restricted to trusted monitoring/admin access.
What should pm.max_requests be set to?
There is no universal value. The documented default is 0, meaning unlimited requests per child. Use a non-zero value when memory trends or library/application behavior justify recycling, and avoid aggressive values that create needless process churn.
Should I test PHP-FPM configuration before reload?
Yes. PHP-FPM supports -t/--test to validate the FPM configuration. Use the binary/config path provided by your distribution, then reload through the supported service manager and verify health immediately afterward.
Can PHP-FPM improve Core Web Vitals?
Only indirectly. Reducing backend queueing or PHP processing time can help initial response and therefore LCP when backend latency is a limiting factor. PHP-FPM does not directly fix INP or CLS.
Should I tune PHP-FPM on managed WordPress hosting?
Only if the provider exposes and supports those controls. Many managed platforms intentionally manage PHP-FPM for you.
Which PHP version should I use?
Use a currently supported branch that is compatible with WordPress, your theme, plugins and extensions. As of September 24, 2026, PHP 8.2 through 8.5 are supported branches; 8.2 and 8.3 are in security-fixes-only support, while 8.4 and 8.5 are in active support. PHP 8.6.0 RC2 is pre-release and should not be used as a production target. Check the current PHP supported-version table before upgrading production systems.
Abdul Shakoor
Founder of Digital Bhatti, an independent technical publication focused on web hosting and infrastructure, WordPress, technical SEO, web performance and automation.
This guide is documentation-led. It does not claim an original Digital Bhatti PHP-FPM benchmark unless reproducible test results and the full environment are explicitly published.