How PHP-FPM Actually Works: FastCGI, Workers, and Process Pools
Backend Engineer with experience building and scaling PHP applications in production environments.
I focus on performance, system behavior, and understanding how backend systems actually work beyond the framework layer.
Currently writing about PHP, backend performance, and production engineering.
In the previous article, we established an important idea: PHP does not run by itself.
Before your framework, before your controllers, there is a runtime layer responsible for executing PHP code in production.
That layer is PHP-FPM.
Now it’s time to go one level deeper and understand how PHP-FPM actually works — without jumping into tuning or configuration yet.
PHP-FPM Is Built on FastCGI
PHP-FPM stands for FastCGI Process Manager.
FastCGI is not a PHP feature.
It is a protocol that allows a web server (like Nginx) to communicate with an external application responsible for executing code.
In simple terms:
Nginx handles HTTP
PHP-FPM handles PHP execution
FastCGI is the communication contract between them
This separation is intentional. It allows PHP to run independently from the web server, improving scalability, isolation, and reliability.
From Request to Execution
When an HTTP request reaches your server, the flow looks like this:
Nginx receives the HTTP request
Nginx decides the request should be handled by PHP
Nginx forwards the request to PHP-FPM using FastCGI
PHP-FPM assigns the request to an available worker process
The worker executes the PHP script
The response is sent back to Nginx, then to the client
Your framework only starts running after PHP-FPM has already accepted the request and assigned it to a worker.
Workers Are Processes, Not Threads
One of the most important details about PHP-FPM is its execution model.
PHP-FPM uses process-based concurrency.
That means:
Each worker is a separate OS process
Each process handles one request at a time
Memory is isolated per process
This model prioritizes stability and isolation over raw efficiency.
If a worker crashes, it doesn’t take down others
If a request leaks memory, it doesn’t corrupt shared state
This design choice explains many PHP characteristics, including its predictable behavior under failure.
What Is a Process Pool?
PHP-FPM organizes workers into pools.
A pool is a group of worker processes that share:
Configuration
Resource limits
Execution rules
Each pool can be tuned independently, allowing different applications or workloads to coexist on the same server.
From PHP-FPM’s perspective, handling a request is simply:
“Is there an available worker in this pool?”
If yes → the request is executed
If no → the request waits in a queue
This is where many production issues silently begin.
Concurrency Is Limited by Design
Unlike event-driven runtimes, PHP-FPM does not dynamically scale concurrency per request.
Concurrency is explicitly bounded by the number of workers.
This means:
PHP-FPM cannot process more simultaneous requests than available workers
Excess requests are queued
No error is thrown by default
From the outside, the application appears “slow”, even though nothing is technically broken.
Understanding this behavior is critical before touching any configuration file.
Why This Model Matters
At this stage, the key takeaway is not how to tune PHP-FPM.
It’s understanding that:
PHP performance is constrained at the process level
Concurrency is finite and predictable
Many “slow code” problems originate before your code runs
Without this mental model, it’s easy to blame frameworks, databases, or infrastructure incorrectly.
Key Takeaways
PHP-FPM is a process manager built on FastCGI
Requests are handled by isolated worker processes
Concurrency is limited by the number of available workers
Queuing happens silently when workers are exhausted
Your framework runs inside this execution model
In the next article, we’ll explore how PHP-FPM configuration choices directly affect performance, and how small misconfigurations can have outsized impact in production.