Why PHP-FPM Process (Worker) Limits Matter: Preventing Server Outages with Standardized Pool Configuration

Why PHP FPM Worker Limits Matter Preventing Server Outages with Standardized Pool Configuration

This page has had its content updated on October 2, 2025 EDT by Jordan

Content Error or Suggest an Edit

Notice a grammatical error or technical inaccuracy? Let us know; we will give you credit!

Introduction

The reason I’m writing this article is simple: I’ve seen far too many servers hosting multiple sites with inconsistent PHP-FPM pool configurations. In many cases, a single poorly tuned site can bring an entire server to its knees. Instead of constantly explaining why load spikes occur or why all the sites on a server slow down, I want to share a standardized approach to PHP-FPM pool configuration.

By applying consistent, well-reasoned settings, you can isolate problems, keep one site from consuming all the server’s resources, and make troubleshooting much more straightforward.

What is PHP-FPM?

PHP-FPM (FastCGI Process Manager) is the service responsible for handling PHP requests on your server. Whenever a visitor hits a PHP-powered site (WordPress, Laravel, etc.), NGINX forwards that request to PHP-FPM, which assigns it to a worker process. That’s unless you have caching enabled, if there is cache available for the requested URL then the visitor will be served the cached content.

Think of PHP-FPM as a factory:

  • If too many procceses (workers) are allowed, the factory runs out of space, energy, or cash (i.e., memory/CPU).
  • The processes (workers) are the employees.
  • Each request is a customer order.
  • If there aren’t enough processes (workers), orders pile up.

What is a PHP-FPM Pool?

A pool is a group of PHP-FPM processes (workers) assigned to a particular site or group of sites. Each pool:

  • Runs under a system user, it’s important that each site has it’s own system user (important for security).
  • Has its own socket or port (so NGINX knows where to send requests).
  • Can be configured separately with specific process manager settings, logging, environment variables and PHP configuration

This isolation is critical, without PHP-FPM pools, all sites would share a single set of PHP-FPM processes, this also means data is shared and you’ll be unable to track what site is doing what to the system resources.

What Are PHP-FPM Processes (aka “PHP Workers”)?

In the hosting industry, providers like WP Engine, Kinsta, and others often talk about “PHP workers.” This is simply another way of describing PHP-FPM processes.

Here’s what that means:

  • Each worker (process) can handle one PHP request at a time.
  • If you have pm.max_children = 8, then your pool can process up to 8 simultaneous PHP requests.
  • If more requests come in than workers are available, they queue until a worker is free.

Common Analogy

Think of workers like cooks in a kitchen:

  • Each cook can make one dish (request) at a time.
  • If you only have 2 cooks but 10 orders come in, 8 customers must wait.
  • Adding more cooks speeds up service — but too many cooks crowd the kitchen and burn resources.

So when a hosting company says “Your plan includes 4 PHP workers” → They’re effectively saying your pool has a cap of 4 PHP-FPM processes handling PHP at once.

What Are My Configuration Options for PHP-FPM Pools?

Each site (pool) in PHP-FPM has its own configuration file under /etc/php/*/fpm/pool.d/*.conf. These settings control how processes (workers) are created, the maximum number that can exist, and their lifespan. Here’s what the key options do:

pm – PHP-FPM Process Manager

There are three options for which PHP-FPM process manager you can use.

  • static: Fixed number of processes (workers). Rarely used unless you know exactly how many you need.
  • dynamic: Common default. Spins up processes (workers)as needed up to pm.max_children.
  • ondemand: Spawns processes (workers)only when needed, then kills them after idle time. Not ideal since there is warm up penalty.

pm.max_children

The maximum number of PHP processes (workers) allowed to be spawned, this is the single most important setting. Too low → requests queue up. Too high → server swaps/crashes.

pm.start_servers

Number of processes (workers) started when PHP-FPM is started and the pool is created. Too low, and the first requests after a restart feel slow; too high, and you waste memory on idle processes (workers).

pm.min_spare_servers

Minimum number of idle processes (workers) to keep waiting for new requests. Ensures traffic spikes don’t overwhelm the pool. If the number of idle processes (workers) drops below this threshold, new ones are spawned of which there is a startup cost and delay.

pm.max_spare_servers

Maximum number of idle processes (workers) allowed, keeps memory use under control. If too many idle processes (workers) exist, PHP-FPM will kill them off.

    pm.max_requests

    Number of requests a process (worker) will handle before being recycled. Prevents memory leaks and long-lived processes from consuming excessive memory. Processes (workers) restart cleanly after pm.max_requests

    What’s a Good Standardized PHP-FPM Pool Configuration?

    While the “perfect” settings depend on your hardware, PHP version, and site workloads, here’s a safe starting point I recommend for most VPS/dedicated setups with multiple sites.

    Attention

    The following configuration is based on 8 workers, this is not taking into account the hardware provided. You should consider how many cores you have on your server and how many workers a core can support and then adapt the below configuration.

    [example.com]
    user = example # Unique to example.com
    group = example # Unique to example.com
    listen = /run/php/php8.2-fpm-example.sock
    
    pm = dynamic
    pm.max_children = 8
    pm.start_servers = 2
    pm.min_spare_servers = 2
    pm.max_spare_servers = 2
    pm.max_requests = 5000
    

    Why this works:

    • pm.max_children = 8
      • Limits a site to 8 PHP processes (workers), preventing runaway processes from consuming all memory. For a small brochure site, this is enough to handle backend edits and form submissions without overcommitting resources. but may need turning if a WooCommerce site or using Event Calendars which is known to take up resources.
    • pm.min_spare_servers = 2 → Keeps 2 processes (workers) always available, reducing latency when handling incoming requests.
    • pm.max_spare_servers = 2 → Caps idle processes (workers) at 2, which is fine for low-traffic sites. For higher-traffic apps, consider setting this higher than pm.min_spare_servers to absorb bursts.
    • pm.max_requests = 5000 → Recycles processes (workers) after 5000 requests. This prevents memory leaks while still taking advantage of OPcache, which is stored in shared memory by the PHP-FPM master and persists across worker restarts.

    From here, you can standardize across sites (e.g., capping most pools at 8–10 processes (workers)). For high-traffic or resource-intensive apps, increase these values carefully while monitoring memory usage.

    How Can I Tell if a PHP-FPM Pool (aka Website) Is Hitting Its Max Children Limit?

    Even with standardized settings, it’s important to know when a site is bumping into its limits. If a pool regularly reaches pm.max_children, requests will queue up and visitors may see slow load times or even timeouts. Fortunately, there are several ways to monitor and confirm this.

    1. System Monitoring (top / htop / atop)

    Tools like htop or atop give you a quick look at CPU, RAM, and processes per user. Since each PHP-FPM pool typically runs under its own Linux user, you can filter by user to see if one site is hogging resources.

    Examples:

    • htop → Press F5 (tree view), then filter by the pool’s user.
    • top -u site1 → Show only processes for the site1 pool user.

    If CPU is maxed out or memory is climbing during traffic spikes, it’s a strong indicator that processes (workers) are at their limit and requests are queuing.

    See the following article for more information.

    dealing with high cpu or memory usage on your wordpress server
    Dealing with High CPU or Memory Usage on your WordPress Site or Server – Managing WP
    You’re here because you’re dealing with a single WordPress site or a server that is utilizing too much CPU or Memory. If it’s the former and you’ve identified
    cropped managing wp faviconmanagingwp.io

    2. PHP-FPM Status Page

    You can enable a per-pool status page to see active processes, idle processes (workers) , and queue size in real time.

    Step 1 – Add to your pool config:

    pm.status_path = /status
    

    Step 2 – Expose it safely via NGINX (with IP restriction or basic auth):

    location ~ ^/(status|ping)$ {
        allow 127.0.0.1;
        deny all;
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php8.2-fpm-site1.sock;
    }
    

    Step 3 – Query it via curl:

    curl http://127.0.0.1/status
    

    Example output:

    pool:                 site1
    process manager:      dynamic
    start time:           01/Oct/2025:10:15:32
    start since:          540
    accepted conn:        231
    listen queue:         0
    max children reached: 5
    active processes:     8
    idle processes:       2
    
    • listen queue > 0 → requests are waiting.
    • max children reached > 0 → pool is hitting its limit.

    3. Error Logs

    PHP-FPM logs warnings when a pool reaches its max children. Common message:

    [WARNING] [pool site1] server reached pm.max_children setting (8), consider raising it
    

    This means all 8 processes (workers) were busy, and new requests had to wait.

    4. Pool-Specific PHP-FPM Logs

    To make debugging easier, configure each pool with its own log file:

    In your pool config:

    php_admin_value[error_log] = /var/log/php8.2-fpm-site1.log
    

    Example log lines:

    [01-Oct-2025 12:45:01] WARNING: [pool site1] server reached pm.max_children setting (8), consider raising it
    [01-Oct-2025 12:45:02] NOTICE: [pool site1] child 12345 exited with code 0 after 5000 requests
    [01-Oct-2025 12:45:02] NOTICE: [pool site1] child 12346 started
    

    How to grep for pool warnings:

    grep "pm.max_children" /var/log/php8.2-fpm-site1.log
    

    Or watch in real time:

    tail -f /var/log/php8.2-fpm-site1.log | grep site1
    

    This makes it clear when a pool is constrained and whether recycling (pm.max_requests) is working as expected.

    With these four methods — process monitoring, the status page, error logs, and dedicated pool logs — you’ll know exactly when a PHP-FPM pool is at capacity and what’s happening inside it.

    What Typically Causes a PHP-FPM Pool to Hit Its Max Children Limit?

    Hitting worker limits isn’t always a “bad” thing — sometimes it’s expected during traffic bursts. But common causes include:

    1. Poorly optimized plugins/themes (WordPress especially). Heavy queries or un-cached requests eat up processes (workers) fast.
    2. No caching layer (NGINX microcaching, Redis object cache, or full-page caching missing). Every request hits PHP unnecessarily.
    3. Too few processes (workers) set in the pool (legit traffic exceeds capacity).
    4. Bots or brute force attacks generating excess PHP requests (e.g., hitting xmlrpc.php).
    5. Memory starvation → if you allow too many processes (workers), they all fight for limited RAM, which tanks the server.

    How to Prevent a PHP-FPM Pool from Hitting Its Limit

    If a site is constantly reaching its pm.max_children limit, it’s a sign that either the pool is under-provisioned or the site is generating more PHP requests than it should. You can address this in a few ways:

    1. Optimize the Application (First Line of Defense)

    • Enable caching: Full-page caching (NGINX microcache, Varnish, or a WordPress plugin like WP Rocket) prevents every request from hitting PHP.
    • Use object caching: Tools like Redis or Memcached reduce repeated database calls.
    • Audit plugins/themes: Some WordPress plugins (e.g., heavy page builders, analytics plugins) can generate dozens of PHP calls per page load. Disable or replace inefficient ones.

    Tip: If you cut the PHP requests in half through caching, you effectively double the capacity of your pool without changing server configs.

    2. Tune Pool Settings Thoughtfully

    • Raise pm.max_children cautiously: If you have enough RAM, increasing processes (workers) gives the pool more capacity. But always calculate memory per worker (max_children × average worker size) to avoid swapping.
    • Adjust spare servers: If bursts are frequent, set pm.min_spare_servers and pm.max_spare_servers slightly higher to keep more processes (workers) ready.

    3. Balance Traffic Across Sites

    On a multi-site server, one pool should never be able to consume all resources. To prevent this:

    • Give each site its own pool with sensible caps. (GridPane and other control panels do this already)
    • Avoid giving one site an oversized max_children setting unless you know it’s justified.
    • If one site consistently outgrows its pool, consider moving it to a separate server or container.

    4. Block Abusive Traffic

    Often, limits are hit because of bots or brute-force requests, not real users.

    • Block or rate-limit abusive paths (e.g., /xmlrpc.php, /wp-login.php) in NGINX.
    • Use fail2ban to block consistent abusers.
    • Cloudflare, or a WAF to cut down unnecessary PHP hits.
    secure protect and lock down your wordpress site with cloudflare custom waf rules was firewall rules
    Secure, Protect and Lock Down your WordPress site with Cloudflare Custom WAF Rules (was Firewall Rules) – Managing WP
    This is a huge article that covers a lot of topics. If you’re looking for the Cloudflare rules I’ve developed, then click on the button below 🙂
    cropped managing wp faviconmanagingwp.io

    5. Monitor and Iterate

    • Use the status page to see if requests are queuing.
    • Check logs for pm.max_children warnings.
    • Track memory usage so you know whether you’re truly at resource limits or just misconfigured.

    Other Resources

    spinning beachball
    PHP Workers and WordPress: The Definitive Guide – Pagely
    PHP workers are getting a bad rap lately in the WordPress hosting world. Most commonly, they’re being cited as a scapegoat for a hard upsell by the host.
    pagely.com

    Conclusion

    You don’t just “raise the limits” blindly. You optimize the app, tune pools safely, isolate sites, block garbage traffic, and monitor usage. That way, PHP-FPM pools stay healthy, and one busy site doesn’t drag down the whole server.

    Standardizing PHP-FPM pool settings is one of the simplest and most effective ways to keep multi-site servers stable. By setting consistent worker limits, isolating sites into their own pools, and monitoring logs for when limits are reached, you can prevent one busy or misbehaving site from taking down everything else.

    From there, you can layer in optimization: caching, database tuning, and selective worker adjustments for high-traffic sites. The key is balance — enough processes (workers) to serve traffic efficiently, but not so many that you risk taking the whole server offline.

    Changelog

    • 10-02-2025
      • Updated reference to workers as processes (workers). Created section What Are PHP-FPM Processes (aka “PHP Workers”)?
      • Added Other Resources section.

    0 Shares:

    You May Also Like