Technology

PHP-FPM Settings for WordPress and WooCommerce: pm, pm.max_children and pm.max_requests

When a WordPress or WooCommerce site feels slow or starts throwing 502/504 errors under load, we often find the root cause in one place: misconfigured PHP-FPM pools. The three settings that matter most are pm, pm.max_children and pm.max_requests. They decide how many PHP workers you really have, how much RAM those workers will eat, and how gracefully they recycle over time. In this article, we will walk through how we at dchost.com choose these values in real projects, from small blogs to busy WooCommerce stores.

We will avoid vague advice like “set it to 50” and instead build a simple, repeatable way to size your PHP-FPM pools based on available RAM, process memory usage and expected concurrency. We will also show how tuning differs between a content site and a checkout-heavy WooCommerce store, and how to verify that your choices are actually working in production. By the end, you should be able to look at a server and say: “this is how many PHP workers it can safely run, and here is the config to match”.

Why PHP-FPM Tuning Matters So Much for WordPress and WooCommerce

WordPress and WooCommerce are both PHP applications. Every uncached page view, AJAX request or admin action runs through PHP-FPM. If PHP-FPM is tuned too small, visitors queue for a free worker and your Time To First Byte (TTFB) rises. If it is tuned too large, workers fight for RAM, the server swaps, and everything becomes slow or unstable.

Unlike simple static hosting, a dynamic site has three critical bottlenecks: CPU, RAM and the database. PHP-FPM sits in the middle, brokering every dynamic request to PHP code and MySQL. That is why we always tune PHP-FPM side by side with MySQL, caching and core PHP ini settings like memory_limit and max_execution_time. For WooCommerce, which has heavier queries and more authenticated traffic, the impact is even stronger.

If you get PHP-FPM right, you usually see three immediate benefits:

  • Lower median and p95 TTFB for uncached requests
  • Far fewer 502/504 gateway errors during traffic spikes
  • Much more predictable CPU and RAM usage under load

Let’s start with a quick reminder of how PHP-FPM works under the hood.

Quick Primer: How PHP-FPM Works

PHP-FPM (FastCGI Process Manager) is a daemon that keeps a pool of PHP worker processes ready to handle incoming requests from the web server (Nginx, Apache with proxy_fcgi, LiteSpeed, etc.). Each worker handles one request at a time. When the request is done, the worker becomes idle and waits for the next one.

Key points to keep in mind:

  • Each worker is a PHP process that consumes RAM. The more plugins and themes you load, the bigger each process becomes.
  • Your effective concurrency is roughly “number of workers” per pool. 10 workers means at most 10 concurrent uncached PHP requests.
  • Workers can be pre-spawned (ready ahead of time) or spawned on demand, depending on the pm mode.
  • Workers are occasionally recycled to avoid memory leaks and long-living processes. This is what pm.max_requests is about.

PHP-FPM settings live in pool config files, usually under /etc/php-fpm.d/ (RedHat/AlmaLinux/Rocky) or /etc/php/*/fpm/pool.d/ (Debian/Ubuntu). On many control panels, each site or account gets its own pool, which is ideal for isolation and per-site tuning. For a deeper, practical look at PHP-FPM itself, you can also read our article on server-side secrets that make WordPress fly with PHP-FPM and OPcache.

Understanding pm, pm.max_children and pm.max_requests

pm: Choosing the Process Manager Mode

The pm setting controls how PHP-FPM manages worker processes. You will typically see one of three values:

  • pm = static: A fixed number of workers equal to pm.max_children are always kept running.
  • pm = dynamic: PHP-FPM keeps a minimum number of workers and scales up to pm.max_children as needed.
  • pm = ondemand: Workers are spawned when requests come in and killed after being idle for a while.

How to choose for WordPress and WooCommerce:

  • dynamic – Our default for most WordPress and WooCommerce setups. It balances resource usage and responsiveness, especially under fluctuating load.
  • static – Good for very stable, high-traffic environments where you know exactly how many workers you need and want predictability over elasticity.
  • ondemand – Useful on very small VPS or low-traffic sites to save RAM when there is no traffic, but it can hurt TTFB on the first request after idle periods.

For typical WooCommerce stores on a VPS, we almost always start with pm = dynamic. On heavily optimized, high-traffic clusters, we sometimes use pm = static for tighter control.

pm.max_children: How Many PHP Workers You Really Have

pm.max_children is the hard cap on how many PHP worker processes can exist in a pool at once. This number effectively defines your maximum concurrent PHP requests for that pool.

If you set this number too low, requests line up waiting for a free worker, and you see increased response times and sometimes 502 errors from the web server (timeout while waiting for PHP). If you set it too high, workers consume more RAM than you actually have, the server starts swapping, and the entire box slows down or even becomes unstable.

Getting pm.max_children right is mostly about RAM math: how big each worker is, and how much memory you can dedicate to PHP-FPM after accounting for MySQL, cache (Redis/Memcached), the OS and other services.

pm.max_requests: Recycling Workers to Avoid Memory Leaks

pm.max_requests tells PHP-FPM how many requests a single worker will handle before it is gracefully restarted. After serving that many requests, PHP-FPM kills the worker and spawns a new one. This helps:

  • Mitigate memory leaks in PHP, extensions or plugins
  • Keep long-living processes from growing too large over time
  • Refresh APCu/OPcache in some edge cases (though OPcache has its own policies)

If pm.max_requests is set too low, workers get recycled too often, adding overhead and occasionally causing short CPU spikes. If it is set too high or left unlimited, memory usage can creep up over days until you suddenly hit swap or OOM kills.

For WordPress/WooCommerce, we typically start with values between 300 and 1,000. Heavier stores with many plugins often benefit from a slightly lower value to keep leaks in check, while simple blogs can afford a higher one.

The Core Formula: How to Size pm.max_children Safely

Let’s build a simple formula you can reuse on any server. The basic idea is:

maximum PHP workers ≈ available RAM for PHP / average RAM per PHP process

We will refine this with safety margins, but that is the foundation.

Step 1: Measure Average PHP-FPM Process Memory

You cannot guess this accurately; plugins and themes change everything. Measure it on your own site under realistic load. On a Linux VPS or dedicated server, run (adjust PHP version/pool name as needed):

ps -o rss,cmd -C php-fpm | grep 'pool=www'

rss is resident set size in KB. You can also use top or htop and look at PHP-FPM processes during a period of active traffic: browse the site, run a few WooCommerce checkouts, open wp-admin, etc.

Example: you observe several PHP-FPM workers using between 120 MB and 180 MB RSS. You can take 160 MB as a conservative average. In KB that is about 160,000, but for easier math we will keep values in MB.

Step 2: Decide How Much RAM You Can Give to PHP-FPM

Your PHP-FPM pool does not own the whole server. On a box running WordPress/WooCommerce you typically have:

  • The OS and background services (SSH, systemd, etc.)
  • Web server (Nginx/Apache/LiteSpeed)
  • Database (MySQL/MariaDB/PostgreSQL)
  • Cache layer (Redis/Memcached), maybe Elasticsearch or OpenSearch
  • Monitoring agents, backup agents, etc.

On a dedicated WordPress/WooCommerce server or NVMe VPS at dchost.com, a reasonable first approximation is:

  • Reserve 30–40% of total RAM for MySQL and caches
  • Reserve 10–20% for OS and web server
  • Give the remaining 40–60% to PHP-FPM

On a small 4 GB VPS, for example, we might budget:

  • 1.2 GB for MySQL + Redis
  • 0.8 GB for OS + Nginx
  • 2.0 GB for PHP-FPM

If you run multiple PHP pools (for multiple sites), that PHP budget must be split across them. Agencies hosting many WordPress sites on one stack often find our guide on hosting architecture for agencies managing 20+ WordPress sites useful here.

Step 3: Compute pm.max_children

Now we divide the PHP-FPM RAM budget by the average process size and add a safety margin:

pm.max_children = floor( PHP_RAM_budget_MB / avg_process_MB ) × safety_factor

We usually use a safety_factor between 0.7 and 0.8 to avoid edging too close to real limits (there are always spikes).

Example 1: Small WordPress Blog on 2 GB VPS

Suppose:

  • Total RAM: 2 GB
  • Average PHP worker RSS: 80 MB
  • We allocate 900 MB to PHP-FPM

Math:

  • Raw max workers: 900 / 80 ≈ 11.25 → 11
  • With 0.8 safety factor: 11 × 0.8 ≈ 8.8 → 8 workers

So we would set:

pm = dynamic
pm.max_children = 8
pm.start_servers = 2
pm.min_spare_servers = 2
pm.max_spare_servers = 4
pm.max_requests = 500

For a low-traffic blog with good full-page caching, 8 workers is usually more than enough.

Example 2: Mid-Size WooCommerce Store on 8 GB NVMe VPS

Now consider a WooCommerce store using many plugins and a heavier theme:

  • Total RAM: 8 GB
  • Measured PHP worker RSS: 150–220 MB → take 200 MB for safety
  • We allocate 3.5 GB to PHP-FPM

Math:

  • Raw max workers: 3,500 / 200 = 17.5 → 17
  • Safety factor 0.75: 17 × 0.75 ≈ 12.75 → 12 workers

Config could look like:

pm = dynamic
pm.max_children = 12
pm.start_servers = 4
pm.min_spare_servers = 4
pm.max_spare_servers = 8
pm.max_requests = 400

This gives you up to 12 concurrent PHP requests. Combined with aggressive full-page caching for anonymous traffic and object caching for logged-in users, this often comfortably handles a few hundred concurrent visitors with occasional checkout bursts. For capacity planning specifically for WooCommerce, we go into more detail in our guide on WooCommerce capacity planning and sizing vCPU/RAM/IOPS.

Example 3: High-Traffic WooCommerce on 16 GB Server

On a busy store, maybe behind a CDN with well-tuned cache rules, you might see:

  • Total RAM: 16 GB
  • Average PHP worker RSS: 250 MB (large plugin stack, heavy theme)
  • PHP-FPM budget: 7 GB

Math:

  • Raw workers: 7,000 / 250 = 28
  • Safety 0.75: 28 × 0.75 = 21 → pm.max_children = 21

Config:

pm = static
pm.max_children = 21
pm.max_requests = 500

Here we might choose pm = static because the store has very predictable high load and we want all 21 workers pre-warmed and ready. This is the sort of configuration we deploy on dedicated WooCommerce servers or higher-end VPS at dchost.com where we know the resource envelope very well.

Choosing pm, pm.max_children and pm.max_requests for WordPress vs WooCommerce

WordPress Blogs and Content Sites

A typical content site has:

  • High ratio of anonymous traffic
  • Effective full-page caching (Nginx microcaching, LiteSpeed Cache, or a CDN)
  • Less complex plugins compared to an e-commerce stack

This means most requests do not hit PHP at all if caching is well configured. For those that do, they are often relatively light. On these sites we often see smaller PHP workers (60–120 MB) and can run more workers per GB of RAM.

For a medium blog on a 4 GB VPS with good caching, a reasonable starting point might be:

pm = dynamic
pm.max_children = 12
pm.start_servers = 3
pm.min_spare_servers = 3
pm.max_spare_servers = 6
pm.max_requests = 800

We also strongly recommend pairing this with good full-page caching. Our article on server-side optimization for WordPress with PHP-FPM, OPcache, Redis and MySQL shows how much relief caching can give your PHP workers.

WooCommerce Stores

WooCommerce changes the picture in a few important ways:

  • More authenticated traffic (logged-in customers and admins)
  • Cart, checkout, My Account and admin are mostly uncacheable as full pages
  • More plugins: payment gateways, shipping, marketing, reporting, etc.
  • More AJAX (cart fragments, live search, shipping calculators)

All of this increases average request cost and inflates PHP worker memory usage. It also means that even with aggressive HTML caching for product/category pages, you must size PHP-FPM for checkout peaks.

For a small WooCommerce store on a 4 GB VPS, we might start with something like:

pm = dynamic
pm.max_children = 8
pm.start_servers = 3
pm.min_spare_servers = 3
pm.max_spare_servers = 6
pm.max_requests = 300

On a bigger 8–16 GB server hosting a single store, 12–24 workers is common, as in the earlier examples. Just remember that increasing pm.max_children increases RAM usage nearly linearly, so you must re-check memory consumption after changes.

pm.max_requests for WordPress and WooCommerce

We almost never leave pm.max_requests at the default of 0 (unlimited). Over days or weeks, you commonly see PHP workers grow in RSS as they handle more complex requests. A moderate recycle limit keeps things in check without causing churn.

Typical ranges we use in real projects:

  • Small WordPress site: pm.max_requests = 800–1,000
  • Medium content or light WooCommerce: 500–800
  • Heavy WooCommerce with many plugins: 300–500

If you notice that PHP-FPM memory usage keeps creeping up over time (e.g., every day RSS grows by a few hundred MB), try lowering pm.max_requests a bit and monitor again.

Typical PHP-FPM Configs for Common Hosting Scenarios

1) Shared Hosting with Limited Access

On shared hosting, you often do not have direct control over pm settings; the provider sets global limits for all accounts. In that situation, your main levers are:

If you constantly hit resource limits on shared hosting, it might be time to move to a VPS where you can control PHP-FPM directly. We have a step-by-step checklist for a smooth transition in our article on moving from shared hosting to a VPS without downtime.

2) Single WordPress Site on a Small VPS (2–4 GB)

For a small business site or blog with moderate traffic on a 2–4 GB VPS, a good starting point is:

  • Measure PHP worker RSS (typically 70–120 MB)
  • Allocate ~40–50% of RAM to PHP-FPM
  • Use pm = dynamic with 6–12 workers

Example for 4 GB RAM, 100 MB workers, 1.5 GB to PHP:

pm = dynamic
pm.max_children = 10
pm.start_servers = 3
pm.min_spare_servers = 3
pm.max_spare_servers = 6
pm.max_requests = 800

Pair this with OPcache enabled (and sized reasonably), a caching plugin, and database tuning and you have a very capable small stack.

3) Single WooCommerce Store on 8–16 GB VPS

For a store that expects real-time traffic, carts and checkouts, we increase both the worker memory estimate and concurrency:

  • Measure PHP worker RSS (often 150–300 MB)
  • Allocate 40–60% of RAM to PHP-FPM
  • Target 12–24 workers, depending on RAM and concurrency needs

Example for 8 GB RAM, 200 MB workers, 3.5 GB to PHP (as before):

pm = dynamic
pm.max_children = 12
pm.start_servers = 4
pm.min_spare_servers = 4
pm.max_spare_servers = 8
pm.max_requests = 400

If your store is growing fast, plan ahead not only for PHP-FPM but also for MySQL, Redis and potential future separation of roles. Our article on when WooCommerce really needs separate database and cache servers explains when this step becomes logical.

4) Multi-Site / Multi-Tenant WordPress on One Server

If you host several sites or a WordPress Multisite network on one VPS or dedicated server, you will typically have:

  • One pool per site (stronger isolation, clearer metrics)
  • Or one pool per cluster of similar sites (simpler config, less overhead)

The formula is the same, but you now split the PHP RAM budget across pools. High-traffic or heavy WooCommerce pools get more workers; small brochure sites get fewer. On dchost.com multi-site stacks, we often allocate a base of 2–4 workers for tiny sites and 6–16 for primary sites.

Monitoring and Iterative Tuning: Did You Get It Right?

PHP-FPM tuning is not a “set once and forget forever” task. Traffic, plugins and code change over time. You should validate your configuration and revisit it regularly, especially after major theme or plugin changes.

Key Things to Monitor

  • PHP-FPM status page (if enabled): see active processes, idle processes, max active, queue length.
  • Server RAM: watch for swap usage; if swap grows steadily, you are likely overcommitted.
  • CPU usage: consistently maxed-out CPU suggests either too many workers or very heavy code.
  • Web server logs: 502/504 errors, upstream timeout errors, long request durations.
  • Access logs: burst patterns around campaigns, newsletters, or sales.

Even simple tools like top, htop, vmstat and journalctl -u php-fpm tell you a lot. For a deeper view on diagnosing slow responses, including TTFB issues caused by PHP-FPM, check out our guide on fixing high TTFB on WordPress and PHP sites.

Symptoms and How to Adjust

Symptom 1: High CPU, but low RAM, frequent 502/504 under spike

  • Possible cause: too many workers, CPU saturated.
  • Action: lower pm.max_children slightly; optimize slow queries and heavy plugins; ensure caching is doing its job.

Symptom 2: RAM constantly near 100%, swap used, system feels sluggish

  • Possible cause: too many workers or oversized memory_limit.
  • Action: reduce pm.max_children, revisit memory_limit, reduce plugin bloat; consider upgrading to a plan with more RAM.

Symptom 3: Requests sometimes wait a long time before PHP starts processing

  • Possible cause: too few workers; PHP-FPM queue building up.
  • Action: increase pm.max_children slightly if RAM allows; verify that caching is correct so you are not wasting workers on anonymous traffic.

Symptom 4: PHP-FPM memory usage grows day by day, then resets after reloads

  • Possible cause: memory leaks, too high or unlimited pm.max_requests.
  • Action: reduce pm.max_requests in steps (e.g., 1,000 → 600 → 400), monitor again.

Putting It All Together: A Practical Checklist

To recap the process we follow for WordPress and WooCommerce sites on dchost.com infrastructure, here is a step-by-step checklist you can adapt:

  1. Enable OPcache and caching (page cache + object cache) so PHP-FPM is not doing unnecessary work.
  2. Measure average PHP worker RSS under realistic load using ps, top or htop.
  3. Define a RAM budget for PHP-FPM after reserving memory for MySQL, caches, OS and other services.
  4. Compute pm.max_children using the formula and add a safety factor of 0.7–0.8.
  5. Pick pm mode: usually pm = dynamic for most sites; static for high-traffic, well-understood stores.
  6. Set pm.max_requests in a moderate range (300–1,000) depending on complexity.
  7. Reload PHP-FPM, monitor RAM/CPU and access logs for a few days.
  8. Iterate: adjust pm.max_children and pm.max_requests based on real data, not guesswork.

As your traffic grows, plan capacity upgrades early instead of waiting for pain. That might mean scaling up to a larger VPS, moving to a dedicated server, or separating database and cache roles. Our articles on WooCommerce capacity planning and when to split database and cache servers can help you design that roadmap.

Conclusion: A Calm, Data-Driven Way to Tune PHP-FPM

Tuning PHP-FPM for WordPress and WooCommerce does not have to be mysterious. Once you understand what pm, pm.max_children and pm.max_requests actually do, the problem turns into straightforward capacity planning: measure how big each worker is, decide how much RAM you can safely spend, and let the math tell you how many workers you can run.

From our experience managing WordPress and WooCommerce workloads on dchost.com servers, the biggest wins come from combining smart PHP-FPM settings with good caching, realistic PHP ini limits and a clean plugin stack. If you are constantly fighting resource limits on shared hosting, or if your WooCommerce checkout slows down during campaigns, it is probably time to look at both your PHP-FPM config and the underlying hosting resources.

If you would like a hosting environment where you control PHP-FPM pools fully and have room to grow, our NVMe VPS, dedicated server and colocation options are designed with exactly these kinds of workloads in mind. Size your server realistically, apply the formulas from this guide, and keep an eye on real-world metrics. With that combination, PHP-FPM stops being a bottleneck and becomes a solid foundation your WordPress or WooCommerce site can grow on.

Frequently Asked Questions

Start by measuring the average memory usage of a PHP-FPM worker under realistic load using tools like ps, top or htop. Then decide how much RAM you can give to PHP-FPM after reserving memory for MySQL, caches, the OS and other services. Divide that PHP RAM budget by the average worker size and apply a safety factor of about 0.7–0.8. The result is a safe pm.max_children value. For example, with 2 GB for PHP-FPM and 150 MB per worker, you get roughly 13 workers raw; with a 0.75 safety factor, you should set pm.max_children to 9 or 10 and monitor usage.

For most WooCommerce stores, pm = dynamic is the most practical choice. It keeps a baseline pool of workers ready and scales up to pm.max_children as traffic increases, which suits stores with variable traffic patterns. pm = static can be useful on larger, dedicated servers with very predictable high load where you want a fixed number of pre-warmed workers. pm = ondemand saves RAM on very low-traffic sites by spawning workers only when needed, but the first request after an idle period can be slower, which is not ideal for busy stores or time-sensitive campaigns.

pm.max_requests controls how many requests a single PHP-FPM worker handles before being recycled. For WooCommerce, which usually has heavier code and more plugins than a simple blog, we recommend moderate values between 300 and 500. This helps avoid long-running workers slowly accumulating memory while avoiding too-frequent restarts that add overhead. If you notice PHP-FPM memory usage creeping up day by day, lower pm.max_requests in steps and re‑monitor. If memory stays stable and you see no OOM or swap pressure, your chosen value is likely healthy.

PHP-FPM tuning significantly affects TTFB for uncached requests, but it is only one piece of the puzzle. Slow database queries, missing full-page caching, heavy plugins, misconfigured object cache and network latency can all contribute to high TTFB. Properly sizing pm, pm.max_children and pm.max_requests ensures that PHP is not a bottleneck under concurrency, but you should also profile slow queries, enable caching and review theme/plugin choices. Our guide on fixing high TTFB for WordPress and PHP sites explains how to diagnose these server-side causes together.

A CDN can offload a large amount of static and even cached HTML traffic, meaning fewer requests reach PHP-FPM. In that case, you might not need as many PHP workers as on a site serving all traffic directly from the origin. However, for logged-in users, admin pages, WooCommerce carts and checkouts, the CDN often cannot cache everything, so PHP-FPM still has to be sized for those critical paths. In practice, we keep the same methodology: measure worker memory, define a PHP RAM budget, calculate pm.max_children and then validate real usage while the CDN is active.