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 -f
Errors 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 = yes
in 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 = 50
50 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 = dynamic
and 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.
Check:
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 memory
Also check:
free -h

4. Primary script unknown

Example:
FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream
The client will usually see:
File not found
and 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.
Check whether the file exists and verify permissions throughout the directory path:
ls -l /var/www/site/index.php
namei -l /var/www/site/index.php
Check the Nginx configuration:
nginx -TPay particular attention to:
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
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).

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:
errnoMessageTypical cause
2No such file or directoryThe socket does not exist: FPM is not running or Nginx points to the wrong socket
13Permission deniedThe Nginx user does not have permission to access the socket
111Connection refusedThe socket exists, but nothing is listening on it (FPM has crashed), or the TCP port is unavailable
11Resource temporarily unavailableThe listen.backlog queue is full because FPM cannot accept requests quickly enough
Check PHP-FPM and the socket:
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-data
listen.group = www-data
listen.mode = 0660
The user running Nginx must either be the socket owner or belong to the appropriate group.

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.
First, check:
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.log

Typical 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.
The 502 status itself does not show the exact cause. You need to check the Nginx error.log and PHP-FPM logs.

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.
Therefore, 504 does not automatically mean that PHP-FPM is the problem.
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.
A long-running SQL query or a hanging external API, however, will more often trigger request_terminate_timeout (which measures real elapsed time) or a 504 from Nginx rather than Maximum execution time exceeded.
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 = 60s
PHP-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.log
request_slowlog_timeout = 5s
The slowlog shows which line and function the script is stuck in, for example an SQL call, curl_exec, file processing, and so on.
(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.
The limit for FPM can usually be increased in the systemd unit using LimitNOFILE= or with the rlimit_files directive in the pool configuration.
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 = /status
In Nginx, allow access only from localhost. Do not expose the status page publicly:
location = /status {
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;
}
Check it with:
curl -s http://127.0.0.1/status
curl -s "http://127.0.0.1/status?full" # detailed information about each process

Main PHP-FPM Settings

Pool settings are usually located approximately here:
/etc/php/8.3/fpm/pool.d/www.conf

pm

Worker management mode: 
pm = dynamic
The 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 = 50
This 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 = 5
The 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 = 500
After 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 errors
journalctl -u php8.3-fpm -n 1003. Check Nginx
tail -n 100 /var/log/nginx/error.log4. Check RAM
free -h5. Check workers
ps aux | grep '[p]hp-fpm'6. Check CPU
top7. If necessary, check disk performance
iostat -xz 1

Quick Error Reference

MessageWhat it meansWhat to check
max_childrenAll workers are busyWorkers, RAM, load
seems busyWorkers are busyLoad frequency and request duration
SIGKILLProcess was forcibly terminatedOOM, RAM
Primary script unknownPHP-FPM could not find the scriptroot, SCRIPT_FILENAME, file
connect() ... failedNginx could not connect to PHP-FPMService, socket, permissions
502Nginx did not receive a valid response from the upstreamNginx + PHP-FPM logs
504Response from the upstream did not arrive in timePHP, database, API, workers, timeout
Maximum execution timePHP exceeded the execution time limitPHP code, database, API
request_terminate_timeoutPHP-FPM terminated a request that took too longDetermine the cause of the long-running request
Too many open filesFile descriptor limit was reachedlimits, sockets, files
listen queueRequests are waiting for a workerWorkers 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.

VPS in the Netherlands

Browse Configurations

SSD Storage VPS

Browse Configurations

Windows SSD Storage VPS

Browse Configurations