Modern web servers handle thousands of HTTP requests every minute, and how your PHP engine processes those requests directly impacts site speed, memory usage, and overall reliability. In this guide, we'll explore PHP-FPM (FastCGI Process Manager) — what it is, how it works compared to older methods, why it's become the standard for production hosting, and how to tune its configuration for peak performance on your VPS or dedicated server.
In short: PHP-FPM is a process manager that maintains a pool of PHP worker processes ready at all times, then routes incoming requests to idle workers — rather than spawning a fresh PHP process for each request (the old CGI way) or embedding PHP directly in Apache (mod_php). This design uses less memory, reduces latency, and increases throughput. To optimize pm.max_children and other tuning parameters to your server's RAM, check DirectAdmin's PHP Selector if available, or contact AsiaGB support for recommendations.
What Is PHP-FPM?
PHP-FPM stands for FastCGI Process Manager, and it's the modern standard for handling PHP on web servers. The core concept is elegant: instead of waiting for an HTTP request to arrive and then spawning a brand-new PHP process from scratch (which takes time), PHP-FPM pre-creates and continuously maintains a "pool" of PHP worker processes. When a request arrives, the master process instantly assigns it to an available worker. If all workers are busy, the request waits in a queue. Think of it like having a team of employees ready at their desks instead of hiring a temp worker from the street for each customer — much faster and more efficient.
PHP-FPM vs. Mod_PHP vs. PHP-CGI
PHP-CGI (legacy): Every time the web server receives a .php request, it spawns a brand-new PHP process, processes the file, outputs the result, and kills the process. This incurs significant CPU overhead (process startup), and under high traffic the server spawns thousands of processes, leading to memory exhaustion and system slowdown or crash.
Mod_PHP (built-in): Embeds the PHP engine directly into Apache's worker processes. No spawning overhead, but each Apache worker carries the full PHP runtime — so a server with 300 Apache workers must load the entire PHP library 300 times. A 4GB server running Mod_PHP often hits swap and becomes unusable.
PHP-FPM (modern): A separate process manager creates a small, managed pool of PHP workers (typically 5–50 processes) that sit idle until requests arrive. When a web server (Nginx or Apache) receives a PHP request, it forwards it to the FPM master process via a Unix socket or TCP connection. The master picks an idle worker, sends the request to it, and if no workers are free, the request queues. This uses a fraction of the memory (no need for 300 PHP processes all day), reduces latency to near-zero, and scales smoothly under load.
| Metric | PHP-CGI | Mod_PHP | PHP-FPM |
|---|---|---|---|
| Process Creation | New per request | Embedded in Apache | Pre-created pool |
| Memory per request | High (startup cost) | Very high (300 procs) | Low (5–50 procs) |
| Latency | High (startup delay) | Low | Very low |
| Scalability | Poor | Fair | Excellent |
| Web Servers Supported | Any | Apache only | Nginx, Apache, others |
Pool Configuration Parameters
The power of PHP-FPM lies in its configurability. Pool settings live in config files like /etc/php/8.1/fpm/pool.d/www.conf (Linux) or via a control panel like DirectAdmin. AsiaGB customers can typically use the DirectAdmin PHP Selector to choose PHP versions and tweak pool parameters without SSH access.
pm (Process Manager mode): Controls how the pool scales.
pm = static: Always maintains exactlypm.max_childrenprocesses. Good for dedicated servers with stable memory.pm = dynamic: Starts withpm.start_serversprocesses, then grows or shrinks betweenpm.min_spare_serversandpm.max_spare_serversto match demand. Ideal for shared hosting with variable traffic.pm = ondemand: Spawns workers only when requests arrive, then idles them out after a timeout. Best for VPS with very sparse traffic.
pm.max_children: The maximum number of worker processes allowed at once. If all pm.max_children processes are busy, new requests queue. Set too high and the server runs out of memory; set too low and high traffic causes 502 Bad Gateway errors or timeouts.
pm.start_servers, pm.min_spare_servers, pm.max_spare_servers: Used only in pm = dynamic mode. You tell FPM: "On startup, create X processes. Keep at least Y idle processes, but no more than Z idle." For example, pm.start_servers = 10, pm.min_spare_servers = 5, pm.max_spare_servers = 20 means FPM boots with 10 workers; if idle falls below 5 it spawns more; if idle exceeds 20 it kills the excess.
pm.max_requests: Recycle a worker process after it handles this many requests. Prevents memory leaks: even if a script has a subtle memory bug that uses 1MB extra per request, recycling after 1000 requests limits the leak. Example: pm.max_requests = 1000 means each worker dies and respawns every 1000 requests.
request_terminate_timeout: Maximum seconds a PHP script can run before FPM force-kills it. Default is often 30 seconds; increase to 300 for background tasks. Note that your web server (Nginx) may have its own timeout too — they stack.
How to Check Your Current PHP Handler
Not sure if your hosting uses PHP-FPM, Mod_PHP, or CGI? Check in a few ways:
Via phpinfo(): Create a file with just <?php phpinfo(); ?>, upload it, and look for "Server API". You'll see "FPM/FastCGI" (PHP-FPM), "Apache 2.0 Handler" (Mod_PHP), or "CGI" (CGI mode).
Via SSH (if you have shell access):
ps aux | grep php
If you see multiple lines like php-fpm: pool www your hosting runs PHP-FPM. If no php processes appear, it's likely Mod_PHP (running inside Apache).
The 502 Bad Gateway Problem
Warning: A common cause of 502 Bad Gateway is undersized pm.max_children. When traffic spikes and all PHP workers are busy, new requests have nowhere to go; the web server can't connect to an available FPM worker and returns 502. Another cause is request_terminate_timeout being too short for long-running scripts; the script gets killed mid-execution and the web server sees a broken connection. The fix: increase pm.max_children (with monitoring to ensure you have enough RAM), or raise request_terminate_timeout if scripts legitimately need more time.
Monitor PHP-FPM with the Status Page
Tip: PHP-FPM includes a hidden status page showing real-time metrics: idle process count, accepted connections, slow request count, and more. To enable it, edit /etc/php/8.1/fpm/pool.d/www.conf (or use DirectAdmin PHP Selector if it exposes the setting) and set pm.status_path = /fpm-status, then restart FPM. You can then query http://localhost/fpm-status from the server's shell (or via SSH tunneling) to see stats like "idle processes: 3 of 10", "slow requests: 0", etc. If "idle processes" is always zero, your pool is too small; if "slow requests" is high, check request_terminate_timeout.
Performance Tuning Guide
The main goal is to right-size pm.max_children so that all requests get a worker quickly, without running out of RAM.
Rough formula:
pm.max_children = (Total Available RAM - OS Overhead) / Average PHP Process Memory
Example: A 4GB VPS, OS + services use ~500MB, and you measure that idle PHP processes use ~30–50MB each (average 40MB):
pm.max_children = (4096 MB - 500 MB) / 40 MB per process ≈ 90 processes
However, don't blindly max it out. Setting 90 processes when each request takes 3–5 seconds means you need ~450 CPU milliseconds per request just to keep all workers busy — that's all your CPU cores pegged. Also consider that high process count increases context-switching overhead. Start conservative, monitor, and grow if needed.
Tuning steps:
- Monitor current memory used by PHP processes (check
topor FPM status page). - Calculate
pm.max_childrenusing the formula above. - Edit the config and set new value, then restart PHP-FPM.
- Immediately check FPM status and logs for errors.
- Run a load test (e.g.,
ab -n 10000 -c 100 http://yoursite.com/) to see if 502 errors appear or latency spikes. - If 502 errors occur, increase
pm.max_childrenfurther. - If the server runs out of memory (check dmesg or system logs for OOM killer), reduce
pm.max_children. - Retest and iterate until stable.
For shared hosting (dynamic mode): If you're constrained and using pm = dynamic, reduce pm.max_spare_servers (to, say, 10 instead of 35) to cut idle memory use, while keeping pm.min_spare_servers reasonable (e.g., 5) for snappy response times.
Multiple Pools for Multiple Sites on One Server
When a single server hosts several websites, sharing one FPM pool across all of them can cause problems: a high-traffic site can starve worker processes away from a lower-traffic site. The fix is to create a separate pool per site by adding new config files in the pool.d/ directory, such as site-a.conf and site-b.conf. Each file defines its own pool name (e.g., [site-a]), listens on a distinct socket like /run/php/site-a.sock, and sets pm.max_children proportional to that site's expected traffic. This way, a runaway script on one site (an infinite loop, for example) does not starve PHP workers for other sites on the same server, since each pool has its own dedicated workers and memory ceiling.
For administrators managing multiple customer accounts, separating pools per domain also improves security: each pool can run as a different user and group (similar to how DirectAdmin's PHP Selector isolates permissions per account), preventing one site's files from being read or written by another site's PHP process even though they share the same physical server. This is a standard isolation technique used by shared hosting providers to keep customer accounts separated.
Nginx and PHP-FPM: Unix Socket vs TCP Connections
When Nginx forwards a request to PHP-FPM, it can connect in one of two ways: via a Unix socket (a file on disk, such as /run/php/php8.1-fpm.sock) or via TCP (e.g., 127.0.0.1:9000). Unix sockets are typically slightly faster since they bypass the OS network stack — ideal when Nginx and PHP-FPM run on the same machine. TCP is necessary when PHP-FPM runs on a separate machine from Nginx, such as an architecture that splits the web server and application server to scale independently. In Nginx's config you'll see a line like fastcgi_pass unix:/run/php/php8.1-fpm.sock; for sockets, or fastcgi_pass 127.0.0.1:9000; for TCP. Either value must match the listen directive set in the FPM pool config, or you'll see errors like "No such file or directory" or "Connection refused."
Summary
PHP-FPM is a cornerstone of modern, high-performance web hosting. By maintaining a managed pool of PHP workers and routing requests intelligently, it eliminates the overhead of process creation and allows servers to handle far more concurrent traffic than older approaches like PHP-CGI or even Mod_PHP. Tuning pm.max_children, pm mode, pm.max_requests, and request_terminate_timeout to match your actual workload prevents 502 errors, reduces latency, and makes the most of your hardware. If you're using DirectAdmin hosting with AsiaGB, check the PHP Selector for these settings, or reach out to our support team for personalized tuning advice.
Frequently Asked Questions
Does PHP-FPM actually make websites faster?
Yes. PHP-FPM keeps worker processes pre-created and ready, eliminating startup overhead every request. Compared to PHP-CGI, which spawns a new process each time, FPM reduces latency dramatically. For high-traffic sites, the difference in perceived speed is substantial.
What should I set pm.max_children to?
Use the formula (Available RAM - OS/Service Overhead) / Average PHP Process Memory. For a 4GB VPS with 40MB per process, aim for ~90. The exact number depends on testing: run load tests and monitor until you reach the sweet spot with no 502 errors and stable memory.
Why does my site return 502 Bad Gateway?
Often because pm.max_children is too low — under traffic spikes, all PHP workers are busy and new requests can't connect to a free worker. Increase pm.max_children, or if scripts legitimately run long, raise request_terminate_timeout.
Do I need SSH to restart PHP-FPM?
Not necessarily. AsiaGB customers can typically use DirectAdmin's PHP Selector to adjust pool settings directly; changes take effect quickly. If your panel doesn't expose the setting, contact AsiaGB support to adjust it for you.
Start Your AsiaGB Hosting Today
AsiaGB Hosting runs on SSD storage, managed through the easy-to-use DirectAdmin control panel, with multi-PHP support and 99% uptime — affordable plans backed by a Thai support team.
See Hosting Plans