Servers & VPS

PHP-FPM Optimization on VPS: Pools, Workers and Settings

Configure PHP-FPM correctly on your VPS by tuning pools, process manager mode, and worker limits to maximize throughput without exhausting RAM.

Closeup of many cables with blue wires plugged in modern switch with similar adapters on blurred background in modern studio

The default PHP-FPM configuration that ships with most Linux distributions is designed to work, not to perform. Optimizing PHP-FPM on a VPS comes down to correctly calculating how many workers you can run in parallel without exhausting available RAM, and separating pools per site so a traffic spike on one domain doesn't drag down the rest.

Why PHP-FPM Configuration Matters

PHP-FPM (FastCGI Process Manager) manages a pool of PHP processes that wait for requests from the web server. Configure too many workers and RAM runs out, the server starts swapping, and performance collapses. Configure too few and requests queue up, causing slow response times or 502 errors.

On a resource-constrained VPS, the exact balance between those two extremes can be the difference between a fast site and a server that crashes at the first traffic peak.

Process Manager Modes (pm)

PHP-FPM offers three process manager modes. Choosing the right one is the first step in optimization:

Mode Behavior When to use it
static Fixed number of workers always active VPS with predictable, constant traffic
dynamic Workers created and destroyed on demand Variable traffic; the most common mode
ondemand Workers only created when a request arrives Small VPS with many idle pools

For most VPS servers running one or more active sites, dynamic is the best choice: it absorbs traffic spikes without wasting RAM during off-peak hours.

Worker Count: The Practical Formula

Before touching any config file, you need to know how much RAM one PHP process consumes on your application. Run this while the site is receiving normal traffic:

ps --no-headers -o rss -C php-fpm | awk '{ sum += $1 } END { print sum/NR/1024 " MB per process" }'

With that number, apply the following formula:

max_children = (RAM available for PHP) / (RAM per process)

Example with a 2 GB VPS

  • Total RAM: 2048 MB
  • OS + MySQL: ~600 MB
  • RAM available for PHP: ~1400 MB
  • RAM per PHP process (typical WordPress): ~35 MB
  • Recommended max_children: ~40

Never set pm.max_children above this result. It's better to be conservative and scale up than to have a server in swap.

Separate Pools per Site

A single global pool is the most common mistake on multi-site VPS servers. One pool per domain offers clear advantages:

  • Isolation: if one site has a spike or a looping bug, it doesn't consume workers from the others.
  • Security: each pool can run under its own Unix user, preventing a compromised site from reading files belonging to another.
  • Observability: each pool has its own log and socket, making diagnosis much easier.

Create one file per site in /etc/php-fpm.d/, for example site1.conf:

[site1]
user = site1
group = site1
listen = /run/php-fpm/site1.sock
listen.owner = nginx
listen.group = nginx

pm = dynamic
pm.max_children = 15
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 5
pm.max_requests = 500

slowlog = /var/log/php-fpm/site1-slow.log
request_slowlog_timeout = 5s

Key parameters explained

  • pm.max_children: the absolute limit of simultaneous workers for this pool.
  • pm.start_servers: workers launched when the pool starts (usually min_spare + (max_spare - min_spare) / 2).
  • pm.min_spare_servers: minimum number of idle workers that must always be available.
  • pm.max_spare_servers: maximum idle workers; any above this number are destroyed.
  • pm.max_requests: each worker restarts after this many requests, preventing memory leaks.
  • request_slowlog_timeout: logs any request taking longer than N seconds — essential for detecting slow scripts.

Additional Performance Tweaks

Beyond pools, there are global and php.ini settings that directly impact performance:

OPcache: mandatory in production

OPcache stores compiled PHP bytecode in memory, eliminating recompilation on every request. Verify it's active and properly sized:

opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60

With a well-sized OPcache, a WordPress site can respond 3-4x faster on repeated requests.

Memory and time limits

Tune these values in the pool config or in php.ini based on your actual needs — not excessively high values:

memory_limit = 128M
max_execution_time = 30
max_input_time = 30

Bumping memory_limit to 512 MB unnecessarily just leaves you less headroom for additional workers.

For more advanced server configurations, visit our complete VPS guides covering Nginx, MariaDB, and security hardening.

Verify and Monitor Your Configuration

Before reloading PHP-FPM, validate the configuration to catch syntax errors:

php-fpm -t

If everything looks good, reload without interrupting active requests:

systemctl reload php-fpm

To monitor status in real time, enable the status socket in your pool:

pm.status_path = /status

Then expose that endpoint via Nginx or Apache on an internal route. You'll see live metrics: active workers, queued requests, and total requests processed — exactly what you need to tune your values based on real data.

Key takeaways

  • Always calculate pm.max_children based on actual per-process RAM consumption, not generic rule-of-thumb values.
  • Use dynamic mode to absorb traffic spikes without wasting resources during low-activity periods.
  • Separate pools per site for resource isolation, better security, and easier troubleshooting.
  • Enable and properly size OPcache — it's the easiest, highest-impact performance improvement available.
  • The slowlog is your best tool for detecting slow scripts before they cause a CPU problem.
  • Always validate with php-fpm -t before reloading.

Not sure what the optimal values are for your specific workload? The specialists at elenlace.com can audit your current PHP-FPM setup, tune each pool, and configure monitoring so your VPS performs at its full potential.

FAQ

How many PHP-FPM workers do I need per GB of RAM?

It depends on your application's actual consumption. For WordPress without heavy plugins, a typical process uses 25-40 MB, which means roughly 25-40 workers per GB allocated to PHP. Always measure with ps --no-headers -o rss -C php-fpm under real traffic conditions.

What's the difference between a Unix socket and a TCP address for the pool?

Unix sockets (.sock files) are faster because they bypass the OS network stack. Use them when Nginx/Apache and PHP-FPM are on the same server. Only use TCP (127.0.0.1:9000) if PHP-FPM runs on a separate server.

How often should I review my PHP-FPM configuration?

Review your settings after any significant traffic change, when installing plugins or modules that increase memory consumption, and at least once every three months as preventive maintenance.

Is ondemand mode a good option for saving RAM?

Yes, but only for pools serving sites with very low or sporadic traffic. For sites with constant traffic, ondemand can introduce noticeable latency on each worker startup. Consider a hybrid approach: dynamic for your primary sites and ondemand for inactive secondary ones.

Prefer it done for you? El Enlace handles hosting and professional web development.

Compare providers

Other providers and guides worth comparing:

← All