Common PHP-FPM Errors: How to Identify and Fix Problems
19 Sep 2026, 05:45:26
PHP-FPM (PHP FastCGI Process Manager) is a PHP process manager. It receives PHP requests from a web server such as Nginx, executes PHP code, and returns the result.Workflow:
Client
↓
Nginx
↓ FastCGI
PHP-FPM
↓
PHP
↓
Database / files / API
↓
PHP-FPM
↓
Nginx
↓
Client
If PHP-FPM is stopped, overloaded, incorrectly configured, or unable to execute a PHP script, the website may return 502, 504, or 500, or simply become slow.
Where to Look for Errors
Check PHP-FPM services:systemctl list-units --type=service | grep fpmFor example, for PHP 8.3:systemctl status php8.3-fpmLogs:Where FPM writes errors depends on the error_log directive in php-fpm.conf. On Debian/Ubuntu, this is often a separate file such as /var/log/php8.3-fpm.log. Meanwhile, journalctl mainly contains systemd messages related to starting and stopping the service. Therefore, check both sources:
grep -E '^\s*error_log' /etc/php/8.3/fpm/php-fpm.conf
tail -n 100 /var/log/php8.3-fpm.log
journalctl -u php8.3-fpm -n 100
journalctl -u php8.3-fpm -fErrors generated by the PHP code itself (Fatal error, warnings) are written to the PHP error log, which is configured separately from the FPM log. To make worker output appear in the FPM log, use:catch_workers_output = yesin the pool configuration.
1. server reached pm.max_children
Example:WARNING: [pool www] server reached pm.max_children setting (50), consider raising it
What it means:
All available PHP-FPM workers are busy:
pm.max_children = 5050 workers → busy
New request → waits for a free worker
This can increase response times and the request queue.
What to check:
Number of PHP-FPM processes:
ps aux | grep '[p]hp-fpm'Memory:free -hPHP-FPM memory usage:ps -o pid,rss,cmd -C php-fpm8.3If workers are consistently reaching pm.max_children, you need to determine why.Do not simply increase pm.max_children. Each worker consumes RAM, so setting the value too high can lead to OOM.
2. seems busy
Example:WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 8 children, there are 0 idle, and 16 total children
What it means:
This message is generated only when:
pm = dynamicand the number of idle workers falls below pm.min_spare_servers, so FPM starts additional processes.
This does not mean that all workers are busy: fewer workers may be busy than the pm.max_children limit.
The message itself is not an error. It indicates a traffic spike or that pm.start_servers / pm.min_spare_servers may be too low.
The problem occurs if the pool constantly reaches pm.max_children (see section 1) and requests start waiting.
3. child exited on signal 9 (SIGKILL)
Example:WARNING: [pool www] child 1234 exited on signal 9 (SIGKILL)
What it means:
The PHP-FPM process was forcibly terminated.
The most common reason is insufficient memory and the OOM Killer. Other possible causes include:
- a memory limit imposed by a container or systemd unit (cgroup);
- a manual kill -9;
- monitoring scripts or a watchdog terminating "stuck" processes.
journalctl -k | grep -Ei 'oom|out of memory|killed process'
dmesg -T | grep -Ei 'oom|out of memory|killed process'If you see a line such as:Out of memory: Killed process 1234 (php-fpm)the problem is related to insufficient RAM, not PHP-FPM parameters.
If the process was killed by a container or cgroup limit, the message may look like:
Memory cgroup out of memoryAlso check:
free -h4. Primary script unknown
Example:FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream
The client will usually see:
File not foundand a 404 status code.
What it means:
PHP-FPM could not find or open the PHP script whose path was passed by Nginx.
Possible causes:
- incorrect root;
- incorrect SCRIPT_FILENAME;
- the file does not exist;
- an error in the Nginx configuration;
- Nginx and PHP-FPM see different filesystems (for example, different Docker containers or a chroot): the path exists for Nginx but not for FPM;
- the pool user does not have execute (x) permission on one of the directories in the path to the file.
ls -l /var/www/site/index.php
namei -l /var/www/site/index.phpCheck the Nginx configuration:nginx -TPay particular attention to:fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;If the file exists but cannot be read, or the extension is not allowed, FPM may return Access denied (403). For allowed extensions, check the security.limit_extensions directive (by default, only .php is allowed).
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
5. connect() to unix:/run/php/... failed
Example in the Nginx error.log:connect() to unix:/run/php/php8.3-fpm.sock failed (2: No such file or directory) while connecting to upstream
What it means:
Nginx could not connect to PHP-FPM through the Unix socket.
The number in parentheses (errno) immediately indicates the type of problem:
| errno | Message | Typical cause |
|---|---|---|
| 2 | No such file or directory | The socket does not exist: FPM is not running or Nginx points to the wrong socket |
| 13 | Permission denied | The Nginx user does not have permission to access the socket |
| 111 | Connection refused | The socket exists, but nothing is listening on it (FPM has crashed), or the TCP port is unavailable |
| 11 | Resource temporarily unavailable | The listen.backlog queue is full because FPM cannot accept requests quickly enough |
systemctl status php8.3-fpm
ls -la /run/php/For example, if php8.3-fpm.sock exists but Nginx is configured to use php8.2-fpm.sock, the connection will not work.Socket permissions are configured in the pool:
listen.owner = www-dataThe user running Nginx must either be the socket owner or belong to the appropriate group.
listen.group = www-data
listen.mode = 0660
6. 502 Bad Gateway
502 is an error in communication between Nginx and the upstream.If the upstream is PHP-FPM, possible causes include:
- PHP-FPM is stopped;
- an incorrect socket;
- PHP-FPM terminated or a worker crashed during the request (SIGSEGV, SIGKILL);
- permission problems;
- TCP connection problems;
- an overloaded listen.backlog queue;
- a worker was terminated by request_terminate_timeout.
tail -n 100 /var/log/nginx/error.logThen:systemctl status php8.3-fpmand:journalctl -u php8.3-fpm -n 100
tail -n 100 /var/log/php8.3-fpm.logTypical Nginx messages associated with 502:
- connect() ... failed (111: Connection refused) — FPM is not listening;
- connect() ... failed (13: Permission denied) — there are no permissions to access the socket;
- connect() ... failed (2: No such file or directory) — the socket does not exist;
- upstream prematurely closed connection while reading response header — the worker died or was killed during the request;
- recv() failed (104: Connection reset by peer) — the connection was reset by PHP-FPM.
7. 504 Gateway Timeout
504 means that Nginx did not receive a response from the upstream within the configured timeout.In error.log, it may look like:
upstream timed out (110: Connection timed out) while reading response header from upstream
For example:
Nginx
↓
PHP-FPM
↓
PHP
↓
MySQL
↓
Long-running SQL query
↓
PHP waits
↓
Nginx timeout
↓
504
Possible causes include:
- slow PHP code;
- a slow SQL query;
- database locks;
- an external API;
- busy PHP-FPM workers;
- a timeout that is too short.
You need to determine at which stage the delay occurs.
8. Maximum execution time exceeded
Example:PHP Fatal error: Maximum execution time of 30 seconds exceeded in /var/www/site/index.php on line 42
The PHP script exceeded the configured max_execution_time limit.
An important detail: on Linux, this limit measures the time actually spent executing PHP code (CPU time). Time spent waiting outside PHP is not counted, including MySQL responses, network calls to APIs, sleep(), and system calls. On Windows, real elapsed time is counted.
Typical causes of this error include:
- heavy computations;
- infinite or excessively long loops;
- processing large amounts of data in memory;
- an application error.
It is important to distinguish between these three limits:
PHP → max_execution_time — CPU time used by the script (30 seconds by default)
PHP-FPM → request_terminate_timeout — real elapsed request time (0 = disabled by default)
Nginx → fastcgi_read_timeout — how long Nginx waits for a response (60 seconds by default)
9. request_terminate_timeout
In the PHP-FPM pool configuration:request_terminate_timeout = 60sPHP-FPM will terminate the worker if the request runs longer than the configured real-time limit.
The log may contain something like:
WARNING: [pool www] child 1234, script '/var/www/site/index.php' (request: "GET /index.php") execution timed out (61.2 sec), terminating
In this case, the client will usually receive 502, because the connection is closed without a response.
If requests regularly reach this limit, do not simply increase the timeout. First determine why the request takes 60 seconds.
PHP
↓
SQL query
↓
Waiting for the database
↓
Worker is busy
↓
Other workers become busy
↓
Queue grows
↓
Response time increases
The main tool for determining the cause is the slowlog. It records the stack trace of a request that runs longer than the specified threshold:
slowlog = /var/log/php8.3-fpm.slow.logThe slowlog shows which line and function the script is stuck in, for example an SQL call, curl_exec, file processing, and so on.
request_slowlog_timeout = 5s
(In containers, writing to the slowlog may require the SYS_PTRACE capability.)
Keep the timeouts consistent with each other. If fastcgi_read_timeout in Nginx is shorter than request_terminate_timeout, the client will receive 504 while the worker may remain busy for longer.
10. Too many open files
Example:Too many open files
The process has reached its limit for open file descriptors.
Check the limit for a specific process:
cat /proc//limitsFind PHP-FPM processes:pgrep -a php-fpmThe problem may be related to a large number of:- files;
- sockets;
- network connections;
- concurrent requests.
This is not a PHP-FPM-specific error, but it can affect its operation.
11. listen queue
The PHP-FPM status page can show:listen queue: 5 — the number of requests currently waiting to be processed.
If the queue keeps growing, PHP-FPM cannot process incoming requests quickly enough.
It is especially important to look at these values together:
active processes — the number of PHP-FPM workers currently processing requests
idle processes — the number of workers that are currently free and waiting for new requests
max active processes — the maximum number of simultaneously active workers reached since PHP-FPM started
listen queue — the number of requests/connections currently waiting for a free PHP-FPM worker
max children reached — how many times PHP-FPM reached pm.max_children, meaning that it hit the maximum allowed number of workers
slow requests — the number of requests that exceeded request_slowlog_timeout (if enabled)
For example:
active processes: 20
idle processes: 0
max active processes: 20
If at the same time:
listen queue: 15
this indicates that requests are already waiting for a free worker.
How to Enable the Status Page
By default, the status page is disabled.In the pool configuration:
pm.status_path = /statusIn Nginx, allow access only from localhost. Do not expose the status page publicly:
location = /status {Check it with:
allow 127.0.0.1;
deny all;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
curl -s http://127.0.0.1/status
curl -s "http://127.0.0.1/status?full" # detailed information about each processMain PHP-FPM Settings
Pool settings are usually located approximately here:/etc/php/8.3/fpm/pool.d/www.confpm
Worker management mode:pm = dynamicThe main modes are:
static — the number of worker processes is fixed.
dynamic — the number of processes changes automatically within the configured limits.
ondemand — processes are created only when requests arrive.
pm.max_children
Maximum number of simultaneously running workers:pm.max_children = 50This is not the number of users.
50 workers means that the pool can process up to 50 PHP requests simultaneously.
pm.start_servers
For dynamic mode:pm.start_servers = 5The number of workers created when the service starts.
pm.min_spare_servers
Minimum number of idle workers:pm.min_spare_servers = 5
pm.max_spare_servers
Maximum number of idle workers:pm.max_spare_servers = 10
pm.max_requests
For example:pm.max_requests = 500After processing the specified number of requests, the worker is restarted.
This can be useful for limiting memory accumulation in a process, for example due to memory leaks in the application or extensions.
How to Properly Diagnose a Problem
Do not immediately change PHP-FPM settings.Use the following sequence:
Website problem
↓
Nginx error.log
↓
PHP-FPM log
↓
PHP-FPM status
↓
Workers / queue
↓
RAM / CPU / Disk
↓
PHP code / Database / API
↓
Fix
↓
Retest
1. Check PHP-FPM
systemctl status php8.3-fpm2. Check errorsjournalctl -u php8.3-fpm -n 1003. Check Nginxtail -n 100 /var/log/nginx/error.log4. Check RAMfree -h5. Check workersps aux | grep '[p]hp-fpm'6. Check CPUtop7. If necessary, check disk performanceiostat -xz 1Quick Error Reference
| Message | What it means | What to check |
|---|---|---|
| max_children | All workers are busy | Workers, RAM, load |
| seems busy | Workers are busy | Load frequency and request duration |
| SIGKILL | Process was forcibly terminated | OOM, RAM |
| Primary script unknown | PHP-FPM could not find the script | root, SCRIPT_FILENAME, file |
| connect() ... failed | Nginx could not connect to PHP-FPM | Service, socket, permissions |
| 502 | Nginx did not receive a valid response from the upstream | Nginx + PHP-FPM logs |
| 504 | Response from the upstream did not arrive in time | PHP, database, API, workers, timeout |
| Maximum execution time | PHP exceeded the execution time limit | PHP code, database, API |
| request_terminate_timeout | PHP-FPM terminated a request that took too long | Determine the cause of the long-running request |
| Too many open files | File descriptor limit was reached | limits, sockets, files |
| listen queue | Requests are waiting for a worker | Workers and pm.max_children |
Key Takeaways
A PHP-FPM problem cannot be diagnosed based on the HTTP status code alone.For example:
502 is a symptom.
But:
connect() to unix:/run/php/php8.3-fpm.sock failed
already provides specific information about a connection problem.
Similarly:
server reached pm.max_children
indicates that all available workers have been used, but it does not explain why they are busy.
Therefore, the correct approach is:
Symptom
↓
Log
↓
Specific cause
↓
Resource check
↓
Fix
↓
Retest
This approach allows you not only to eliminate a 502/504 error, but also to identify the actual cause of the problem — whether it is PHP-FPM, PHP code, the database, memory, disk, or an external connection.