> ## Documentation Index
> Fetch the complete documentation index at: https://developer.upsun.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Why you can't just add infinite PHP-FPM workers

> Workers need memory. Learn how PHP-FPM sizing hints work, why you can't just add infinite workers, and how to tune your worker count based on actual memory usage.

export const PostMeta = ({data = {}}) => {
  const {author, date, image} = data;
  const authors = Array.isArray(author) ? author : author ? [author] : [];
  const resolveAuthor = slug => {
    const entry = AUTHOR_MAP[slug] || ({});
    const name = entry.name || slug;
    const github = entry.github || null;
    const linkedin = entry.linkedin || null;
    const url = github ? `https://github.com/${github}` : linkedin || null;
    const avatarUrl = github ? `https://github.com/${github}.png?size=64` : null;
    return {
      name,
      url,
      avatarUrl
    };
  };
  const formattedDate = date ? new Date(date).toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric'
  }) : null;
  if (!image && authors.length === 0 && !formattedDate) return null;
  const AUTHOR_MAP = {
    "aaron-collier": {
      "name": "Aaron Collier"
    },
    "aaron-dudenhofer": {
      "name": "Aaron Dudenhofer"
    },
    "aaron-porter": {
      "name": "Aaron Porter"
    },
    "adriaan-odendaal": {
      "name": "Adriaan Odendaal"
    },
    "ajmal": {
      "name": "Ajmal Siddiqui"
    },
    "akalipetis": {
      "name": "Antonis Kalipetis"
    },
    "alexander-varwijk": {
      "name": "Alexander Varwijk"
    },
    "alicia-bevilacqua": {
      "name": "Alicia Bevilacqua"
    },
    "amelie-deguerry": {
      "name": "Amelie Deguerry"
    },
    "anacidre": {
      "name": "Ana Cidre",
      "linkedin": "https://www.linkedin.com/in/ana-cidre"
    },
    "andoni": {
      "name": "Andoni Auzmendi"
    },
    "andrei-taranu": {
      "name": "Andrei (Alex) Taranu",
      "linkedin": "https://www.linkedin.com/in/andrei-alex-taranu/"
    },
    "andrew-baxter": {
      "name": "Andrew Baxter"
    },
    "andrew-melck": {
      "name": "Andrew Melck"
    },
    "antoine-crochet-damais": {
      "name": "Antoine Crochet Damais"
    },
    "augustin-delaporte": {
      "name": "Augustin Delaporte",
      "linkedin": "https://www.linkedin.com/in/augustindelaporte/"
    },
    "branislav-bujisic": {
      "name": "Branislav Bujisic"
    },
    "carl-smith": {
      "name": "Carl Smith"
    },
    "caroline-leroy": {
      "name": "Caroline Leroy"
    },
    "cati-mayer": {
      "name": "Cati Mayer"
    },
    "catplat": {
      "name": "C Trinkwon"
    },
    "ceelolulu": {
      "name": "Celeste van der Watt"
    },
    "chadwcarlson": {
      "name": "Chad Carlson",
      "github": "chadwcarlson",
      "linkedin": "https://www.linkedin.com/in/chadwcarlson"
    },
    "chris-ward": {
      "name": "Chris Ward"
    },
    "chris-yates": {
      "name": "Chris Yates"
    },
    "christian-sieber": {
      "name": "Christian Sieber"
    },
    "christopher-lockheardt": {
      "name": "Christopher Lockheardt"
    },
    "christopher-skene": {
      "name": "Christopher Skene"
    },
    "chuck-morgan": {
      "name": "Chuck Morgan"
    },
    "corey-dockendorf": {
      "name": "Corey Dockendorf"
    },
    "crell": {
      "name": "Crell"
    },
    "damz": {
      "name": "Damz"
    },
    "dan-morrison": {
      "name": "Dan Morrison"
    },
    "davidbonachera": {
      "name": "David Bonachera",
      "github": "davidbonachera",
      "linkedin": "https://www.linkedin.com/in/davidbonachera"
    },
    "dereliahmet1": {
      "name": "Ahmet Faruk Dereli"
    },
    "devicezero": {
      "name": "Jonas Kröger",
      "github": "devicezero",
      "linkedin": "https://www.linkedin.com/in/jonaskroeger/"
    },
    "doug-goldberg": {
      "name": "Doug Goldberg"
    },
    "duncan-naves": {
      "name": "Duncan Naves",
      "github": "duncannaves",
      "linkedin": "https://www.linkedin.com/in/duncan-naves-a94423aa"
    },
    "erika-bustamante": {
      "name": "Erika Bustamante"
    },
    "fabpot": {
      "name": "Fabien Potencier"
    },
    "flovntp": {
      "name": "Florent Huck",
      "github": "flovntp",
      "linkedin": "https://www.linkedin.com/in/florenthuck"
    },
    "fred-plais": {
      "name": "Fred Plais"
    },
    "gauthier-garnier": {
      "name": "Gauthier Garnier"
    },
    "gilzow": {
      "name": "Paul Gilzow"
    },
    "gmoigneu": {
      "name": "Guillaume Moigneu",
      "github": "gmoigneu",
      "linkedin": "https://www.linkedin.com/in/guillaumemoigneu/"
    },
    "gregqualls": {
      "name": "Greg Qualls"
    },
    "guguss": {
      "name": "Augustin Delaporte"
    },
    "haylee-millar": {
      "name": "Haylee Millar"
    },
    "ivana-kotur": {
      "name": "Ivana Kotur"
    },
    "jackrabbithanna": {
      "name": "Mark Hanna"
    },
    "jared-wright": {
      "name": "Jared Wright",
      "github": "jww-sh",
      "linkedin": "https://www.linkedin.com/in/jaredwaynewright"
    },
    "jessica-orozco": {
      "name": "Jessica Orozco"
    },
    "joey-stanford": {
      "name": "Joey Stanford"
    },
    "john-grubb": {
      "name": "John Grubb"
    },
    "jonas-kruger": {
      "name": "Jonas Kruger"
    },
    "kathryn-frazer": {
      "name": "Kathryn Frazer"
    },
    "kemiojo": {
      "name": "Kemi Elizabeth Ojogbede"
    },
    "kieronsambrook-smith": {
      "name": "Kieronsambrook Smith"
    },
    "laurent-arnoud": {
      "name": "Laurent Arnoud"
    },
    "letoya-boyne": {
      "name": "Letoya Boyne"
    },
    "lolautruche": {
      "name": "Jérôme Vieilledent"
    },
    "lyly-lepinay": {
      "name": "Lyly Lepinay"
    },
    "manauwar-alam": {
      "name": "Manauwar Alam"
    },
    "marc-antoine-porri": {
      "name": "Marc Antoine Porri"
    },
    "maria-antinkaapo": {
      "name": "Maria Antinkaapo"
    },
    "maria-de-anton": {
      "name": "Maria De Anton"
    },
    "mark-dorison": {
      "name": "Mark Dorison"
    },
    "markus-hausammann": {
      "name": "Markus Hausammann"
    },
    "mary-thomas": {
      "name": "Mary Thomas"
    },
    "mathias-bolt-lesniak": {
      "name": "Mathias Bolt Lesniak"
    },
    "mathieu-strauch": {
      "name": "Mathieu Strauch"
    },
    "matthias-van-woensel": {
      "name": "Matthias Van Woensel",
      "linkedin": "https://www.linkedin.com/in/matthias-van-woensel-267a069"
    },
    "michael-sharp": {
      "name": "Michael Sharp"
    },
    "mupsi": {
      "name": "Marine Gandy"
    },
    "natalie-harper": {
      "name": "Natalie Harper"
    },
    "ngommenginger": {
      "name": "Nicolas Gommenginger",
      "linkedin": "https://www.linkedin.com/in/nicolas-gommenginger"
    },
    "nicholas-bennison": {
      "name": "Nicholas Bennison"
    },
    "nicholas-vahalik": {
      "name": "Nicholas Vahalik"
    },
    "nick-hardiman": {
      "name": "Nick Hardiman"
    },
    "nickanderegg": {
      "name": "Nickanderegg"
    },
    "nicolas-grekas": {
      "name": "Nicolas Grekas",
      "github": "nicolas-grekas",
      "linkedin": "https://www.linkedin.com/in/nicolasgrekas/"
    },
    "niti-malwade": {
      "name": "Niti Malwade"
    },
    "opensocialteam": {
      "name": "Opensocialteam"
    },
    "ori-pekelman": {
      "name": "Ori Pekelman"
    },
    "otavio-santana": {
      "name": "Otavio Santana"
    },
    "palwandi": {
      "name": "Pawan Alwandi",
      "github": "pawpy",
      "linkedin": "https://www.linkedin.com/in/pawanalwandi"
    },
    "patrick-boest": {
      "name": "Patrick Boest"
    },
    "patrick-dawkins": {
      "name": "Patrick Dawkins",
      "github": "pjcdawkins",
      "linkedin": "https://www.linkedin.com/in/patrickdawkins"
    },
    "patrick-klima": {
      "name": "Patrick Klima"
    },
    "pjcdawkins": {
      "name": "Pjcdawkins"
    },
    "prineet-kaurbhurji": {
      "name": "Prineet Kaurbhurji"
    },
    "quentin-sinig": {
      "name": "Quentin Sinig"
    },
    "ralt": {
      "name": "Florian Margaine",
      "github": "ralt",
      "linkedin": "https://www.linkedin.com/in/florian-margaine-43971136"
    },
    "ramanathanramakrishnamurthy": {
      "name": "Ramanathanramakrishnamurthy"
    },
    "remi-lejeune": {
      "name": "Rémi Lejeune"
    },
    "ribel": {
      "name": "Taras Kruts"
    },
    "robert-douglass": {
      "name": "Robert Douglass"
    },
    "rudy-weber": {
      "name": "Rudy Weber"
    },
    "ryan-hicks": {
      "name": "Ryan Hicks"
    },
    "sabri-helal": {
      "name": "Sabri Helal"
    },
    "savannah-bergeron": {
      "name": "Savannah Bergeron"
    },
    "shannon-vettes": {
      "name": "Shannon Vettes"
    },
    "shawn-ogasawara": {
      "name": "Shawn Ogasawara",
      "linkedin": "https://www.linkedin.com/in/shawn-ogasawara-83a9a0/"
    },
    "shawna-spoor": {
      "name": "Shawna Spoor"
    },
    "shedrack-akintayo": {
      "name": "Shedrack Akintayo"
    },
    "simon-ruggier": {
      "name": "Simon Ruggier"
    },
    "sophie-van-der-kindere": {
      "name": "Sophie Van Der Kindere"
    },
    "stefanos-thampis": {
      "name": "Stefanos Thampis"
    },
    "stephen-weinberg": {
      "name": "Stephen Weinberg"
    },
    "sukhman-virk": {
      "name": "Sukhman Virk"
    },
    "sumaira-nazir": {
      "name": "Sumaira Nazir"
    },
    "sumer": {
      "name": "Sümer Cip"
    },
    "syed-raza": {
      "name": "Syed Raza"
    },
    "tamara-bacchia": {
      "name": "Tamara Bacchia"
    },
    "tara-arnold": {
      "name": "Tara Arnold"
    },
    "theosakamg": {
      "name": "Mickael Gaillard",
      "github": "theosakamg"
    },
    "thomasdiluccio": {
      "name": "Thomas di Luccio"
    },
    "tim-anderson": {
      "name": "Tim Anderson"
    },
    "tom-helmer-hansen": {
      "name": "Tom Helmer Hansen"
    },
    "tylermills": {
      "name": "Tyler Mills"
    },
    "upsun": {
      "name": "Upsun"
    },
    "veronika-tolkachova": {
      "name": "Veronika Tolkachova",
      "linkedin": "https://www.linkedin.com/in/veronika-tolkachova-169167a2"
    },
    "vince-parker": {
      "name": "Vince Parker"
    },
    "vinnie-russo": {
      "name": "Vincenzo Russo"
    },
    "vrobert78": {
      "name": "Vincent Robert",
      "github": "vrobert78",
      "linkedin": "https://www.linkedin.com/in/vincent-robert-498a883"
    },
    "yuriy-babenko": {
      "name": "Yuriy Babenko"
    },
    "yuriy-gerasimov": {
      "name": "Yuriy Gerasimov"
    }
  };
  return <div className="post-meta">
      {(authors.length > 0 || formattedDate) && <div className="post-meta-info">
          {authors.length > 0 && <div className="post-meta-authors">
              {authors.map(slug => {
    const {name, url, avatarUrl} = resolveAuthor(slug);
    const inner = <>
                    {avatarUrl && <img src={avatarUrl} alt={name} className="post-meta-avatar" />}
                    <span className="post-meta-author-name">{name}</span>
                  </>;
    return url ? <a key={slug} href={url} target="_blank" rel="noopener noreferrer" className="post-meta-author">
                    {inner}
                  </a> : <span key={slug} className="post-meta-author">{inner}</span>;
  })}
            </div>}
          {authors.length > 0 && formattedDate && <span className="post-meta-separator" aria-hidden="true">·</span>}
          {formattedDate && <span className="post-meta-date">{formattedDate}</span>}
        </div>}
      {image && <img src={image} alt="" className="post-meta-image" aria-hidden="true" />}
    </div>;
};

<PostMeta data={{ author: ["matthias-van-woensel"], date: "2025-12-08T00:00:00+00:00", image: "/images/posts/insights/why-you-cant-just-add-infinite-php-fpm-workers/why-you-cant-just-add-infinite-php-fpm-workers.webp" }} />

After reading about [PHP-FPM worker exhaustion and 502 errors](/posts/how-it-works/when-php-fpm-runs-out-of-workers-a-502-error-field-guide), the obvious question is: why not add more workers?

If workers are like highway lanes, why don't we build highways with 20 lanes? Because lanes need space. They have to sit somewhere. For PHP-FPM workers, that space is measured in memory.

Here's the math: if each request needs 50MB of memory to process, and your container has 512MB of memory total, you can theoretically fit 10 workers (10 × 50MB = 500MB, with 12MB left over).

That's an oversimplification - nginx needs memory, SSH needs memory, the container itself needs overhead. But that's the basic constraint: workers consume memory, and you only have so much memory available.

## What Upsun does automatically

On Upsun, we calculate your worker count automatically using this formula:

```
worker_count = (container_memory - reserved_memory) / request_memory
```

For example, with a 256MB container using default settings (45MB request memory, 70MB reserved memory):

```
worker_count = (256 - 70) / 45 = 4.13 → 4 workers (rounded down, minimum 2)
```

With a 512MB container:

```
worker_count = (512 - 70) / 45 = 9.8 → 9 workers
```

You can see the full details in the [PHP-FPM documentation on Upsun docs](https://docs.upsun.com/languages/php/fpm.html).

The defaults (45MB request memory, 70MB reserved memory) work fine for most Drupal and WordPress sites. But they're not always right for your application.

## When the defaults don't fit

If you're running Magento, 45MB per request might not be enough - you're going to run out of container memory before you run out of workers. Your metrics will show 100% memory utilization and Out Of Memory kills.

If you're running a lightweight API, you might only need 4MB per request. The system is assuming 45MB, so you're underutilizing your memory and running fewer workers than you could support.

This is when you want to adjust sizing hints.

### Understanding sizing hints

Sizing hints are exactly that: hints. They're not limits or restrictions. They tell Upsun how to calculate the number of workers to allocate.

You configure them in your `.upsun/config.yaml`:

```yaml theme={null}
web:
  sizing_hints:
    request_memory: 45  # MB per request
    reserved_memory: 70 # MB reserved for non-worker processes
```

Here's the counterintuitive part: **you lower request memory to increase worker count**, because it's a division. If you set `request_memory: 35` instead of `45`, you get more workers for the same container size.

Some people get this backwards and think "more is better." It's not. Lower request memory tells the system "my requests are lighter, I can support more workers."

### Finding your actual memory usage

You can check how much memory your requests actually use by analyzing your PHP access logs:

```bash theme={null}
upsun log --lines 5000 php.access | awk '{print \$6}' | sort -n | uniq -c
```

This shows memory usage for each request. You'll see output like:

```
    342 2048
    856 4096
   1205 8192
    234 16384
     12 32768
```

Those numbers are in kilobytes. Most requests hover around the same range. Take a representative average and use that as your `request_memory` value (converted to MB).

This isn't an exact science. Not all requests use the same memory. Some take 40MB, some take 20MB, some take 100MB. You're not utilizing all workers at the same time. The goal is to find a reasonable average that keeps your memory utilization under 100% while maximizing worker availability.

### Tuning in small increments

If you decide to adjust sizing hints, do it gradually:

1. Start with your current value (default is 45MB)
2. Lower it by 10MB (to 35MB)
3. Check your metrics - are you still under 100% memory utilization?
4. Wait a day and verify the system is stable
5. If you need more workers, lower it another 10MB
6. Repeat until you find the right balance

If you go too low, you'll see high memory utilization in your metrics dashboard and potentially Out Of Memory kills in your logs. Back it off by 10MB and stabilize there.

Also watch your CPU usage. More workers mean more CPU load. Upsun's container profiles balance CPU and memory, so this usually isn't an issue if you're using the right profile. But if you're manually adjusting container resources, keep an eye on it.

### CPU limits and worker caps

To ensure that Upsun doesn't add more workers than the CPU can handle, a CPU limit applies as soon as the number of set workers equals or exceeds 25. This limit is calculated as: **number of vCPU cores × 5**.

For example, with 8 vCPUs, you can have a maximum of 40 workers (8 × 5 = 40) - even if you have enough memory to support more.

Why? Because the CPU has to switch between all these processes. If you give it too many workers, context switching overhead becomes a problem. When 8 vCPUs are juggling 40 different tasks (5 per vCPU), they're already working hard. Going beyond that makes things slower, not faster.

## Sizing hints vs memory limit

Let's clarify the difference between sizing hints and PHP memory limit, since they're often confused:

**Sizing hints** (`request_memory`, `reserved_memory`):

* Used to calculate worker count
* Not enforced as limits
* Hints for capacity planning
* Lower values = more workers allocated

**PHP memory limit**:

* Enforced per-request by PHP itself
* Kills requests that exceed the limit
* Protects the container from runaway processes
* Logs violations for debugging

If you set `request_memory: 45` but one request uses 50MB, nothing bad happens. The sizing hints are averages, not hard limits.

If you set `memory_limit: 128M` and a request tries to use 200MB, that request gets killed. See our article on [why you shouldn't set your PHP memory limit to 60GB](/posts/insights/why-setting-your-php-memory-limit-to-60gb-wont-help) for more details.

## Finding the right balance

When you understand what these settings actually do, you can tune them appropriately for your application. The goal is to find the sweet spot where:

* Your workers have enough memory to handle typical requests
* You have enough workers to handle concurrent traffic
* Your memory utilization stays under 100%
* Your CPU isn't overwhelmed by context switching

Start with the defaults, measure your actual usage, and adjust gradually. Don't try to optimize prematurely - let real-world traffic patterns guide your tuning.

## Ready to get started?

If you're dealing with 502 errors and worker exhaustion issues, check out our companion article: [When PHP-FPM Runs Out of Workers: A 502 Error Field Guide](/posts/how-it-works/when-php-fpm-runs-out-of-workers-a-502-error-field-guide).

Want to see how Upsun handles PHP-FPM configuration automatically? [Sign up for a free trial](https://upsun.com) and deploy your first project.
