Diagnosing 'Too Many Open Files' in Nginx & PHP-FPM: A Deep Dive into Sysctl and LimitNOFILE

Resolve the dreaded 24: Too many open files EMFILE error in Nginx and PHP-FPM. Learn how to diagnose and increase file descriptor limits via sysctl and systemd.

Diagnosing 'Too Many Open Files' in Nginx & PHP-FPM: A Deep Dive into Sysctl and LimitNOFILE

Diagnosing ‘Too Many Open Files’ in Nginx & PHP-FPM: A Deep Dive into Sysctl and LimitNOFILE

When dealing with high-traffic web architectures, one of the most insidious errors you can encounter is the dreaded EMFILE error. In an Nginx and PHP-FPM stack, this typically manifests as HTTP 500 or 502 Bad Gateway errors, accompanied by specific log entries.

Unlike misconfigurations related to worker_connections or max_children exhaustion, the Too many open files error points to a fundamental operating system bottleneck: file descriptor exhaustion.

In this guide, we will strictly explore how to diagnose and permanently resolve this issue using kernel sysctl parameters, systemd LimitNOFILE directives, and process-level file limits.

Identifying the EMFILE Error

In Unix-like systems, everything is a file—including network sockets. When your Nginx reverse proxy handles a request, it uses file descriptors to read the client request, communicate with the upstream PHP-FPM socket, and access static assets on the filesystem.

When the file descriptor limit is hit, your Nginx error logs (/var/log/nginx/error.log) will look like this:

2026/09/20 15:42:10 [crit] 18452#18452: *120444 open() "/usr/share/nginx/html/index.php" failed (24: Too many open files), client: 192.168.1.50, server: example.com, request: "GET / HTTP/2.0"
2026/09/20 15:42:10 [alert] 18452#18452: *120445 socket() failed (24: Too many open files) while connecting to upstream, client: 192.168.1.51, server: example.com, request: "GET /api/data HTTP/2.0", upstream: "fastcgi://unix:/run/php/php8.2-fpm.sock:"

Similarly, PHP-FPM logs (/var/log/php8.2-fpm.log) might output:

[20-Sep-2026 15:42:11] ERROR: failed to prepare the listen socket: Too many open files (24)

Step 1: Checking Current Process Limits

Before changing any configuration, verify what limits the operating system is currently enforcing on your Nginx and PHP-FPM processes.

You can inspect the Max open files limit directly from the /proc filesystem. Let’s check Nginx:

cat /proc/$(cat /var/run/nginx.pid)/limits | grep -i "Max open files"

Output:

Max open files            1024                 4096                 files

Here, the soft limit is 1024, and the hard limit is 4096. For a high-performance server, 1024 is drastically insufficient.

Step 2: Tuning the Kernel fs.file-max

The Linux kernel has a global limit on the maximum number of file handles it will allocate. Before increasing limits for specific services, ensure the global ceiling is high enough.

Check the current global limit:

sysctl fs.file-max

If the value is low (e.g., < 100000), increase it by editing /etc/sysctl.conf:

echo "fs.file-max = 2097152" >> /etc/sysctl.conf
sysctl -p

This sets the global limit to roughly 2 million, which provides ample headroom. However, kernel tuning alone won’t solve the issue if shared hosting environments rigidly enforce lower container limits. In such scenarios, bypassing shared server kernel restrictions often requires migrating to highly tunable bare-metal Dedicated Servers in Pakistan or globally provisioned Dedicated Servers, where you have unrestricted root access to kernel parameters.

Step 3: Overriding Systemd LimitNOFILE

Modern Linux distributions manage services via systemd. A common mistake sysadmins make is editing /etc/security/limits.conf and wondering why the changes do not apply to Nginx or PHP-FPM. Systemd ignores /etc/security/limits.conf for system services.

You must configure systemd unit overrides.

For Nginx:

Create a drop-in directory and override file for the Nginx service:

mkdir -p /etc/systemd/system/nginx.service.d
cat <<EOF > /etc/systemd/system/nginx.service.d/override.conf
[Service]
LimitNOFILE=65535
EOF

For PHP-FPM:

Apply the same logic to your PHP-FPM service (adjust the version accordingly, e.g., php8.2-fpm):

mkdir -p /etc/systemd/system/php8.2-fpm.service.d
cat <<EOF > /etc/systemd/system/php8.2-fpm.service.d/override.conf
[Service]
LimitNOFILE=65535
EOF

Reload the systemd daemon to recognize the new drop-in files:

systemctl daemon-reload

Step 4: Application-Level Configuration

Finally, explicitly instruct Nginx and PHP-FPM to request these higher limits from the OS.

Nginx worker_rlimit_nofile

Open your main Nginx configuration file (/etc/nginx/nginx.conf) and add or modify the worker_rlimit_nofile directive in the main context (outside the events block):

user www-data;
worker_processes auto;
worker_rlimit_nofile 65535; # Matches LimitNOFILE
pid /run/nginx.pid;

events {
    worker_connections 16384; 
    multi_accept on;
}

PHP-FPM rlimit_files

Edit your PHP-FPM pool configuration file (typically /etc/php/8.2/fpm/pool.d/www.conf):

; Set open file descriptor rlimit.
; Default Value: system defined value
rlimit_files = 65535

Step 5: Restart and Verify

Restart both services to apply the new configurations:

systemctl restart nginx
systemctl restart php8.2-fpm

Now, re-verify the limits using the /proc filesystem:

cat /proc/$(cat /var/run/nginx.pid)/limits | grep -i "Max open files"

Output:

Max open files            65535                65535                files

Conclusion

The 24: Too many open files error can bring your web stack to a grinding halt under load. By methodically increasing the kernel fs.file-max, configuring systemd LimitNOFILE drop-ins, and explicitly defining worker_rlimit_nofile and rlimit_files at the application level, you can eliminate file descriptor bottlenecks and ensure your Nginx and PHP-FPM infrastructure remains highly available.