Troubleshooting

Too many open files on Linux: find the process, raise the right limit, catch the leak

A process hit its open-file limit (EMFILE), 1024 by default under systemd. Check /proc/PID/limits, raise LimitNOFILE or worker_rlimit_nofile, rule out leaks.

Published ~9 min read

Short answer: “Too many open files” is error 24, EMFILE: one process has as many file descriptors open as its RLIMIT_NOFILE limit allows, and files, sockets and pipes all count. Services started by systemd get a soft limit of 1024 unless the program raises it itself. Find the process, compare its open descriptors with its limit, raise the limit where the process is started (a systemd drop-in, worker_rlimit_nofile for nginx, ulimits for a container), and check whether the count keeps climbing, which means a leak.

Linux · find the limit and the count
pgrep -a nginx                                  # PIDs and command lines; use your process name
grep 'Max open files' /proc/PID/limits
sudo ls /proc/PID/fd | wc -l

Real output for an nginx worker on Debian 12 with the stock limits:

Example output · /proc/PID/limits
Max open files            1024                 524288               files     

The first number is the soft limit, the one that triggers the error; the second is the hard limit, the ceiling up to which the soft limit can be raised without root. If the count from /proc/PID/fd is close to the soft limit, you have found the process.

Which message do you see?

MessageFromMeaning
accept4() failed (24: Too many open files)nginx error.log, level critA worker cannot accept new clients; nginx stops accepting for a moment and visitors wait or time out. Fix
socket() failed (24: Too many open files) while connecting to upstreamnginx, level alertNo descriptor left for the connection to your app; nginx answers that request with 500 Internal Server Error
open() "/var/www/…" failed (24: Too many open files)nginxA static file could not be opened
768 worker_connections are not enoughnginx, level alertA different limit: the connection slots per worker. Raise worker_connections, and the file limit with it
4096 worker_connections exceed open file resource limit: 1024nginx, warning at startnginx is configured for more connections than its file limit allows
Error: EMFILE: too many open files, open '…'Node.jsThe process limit; Node raises its own soft limit, so it is usually a leak
OSError: [Errno 24] Too many open files: '…'PythonThe process limit, often still the default 1024. Raise it
java.io.IOException: Too many open files, FileNotFoundException: … (Too many open files)JavaThe process limit; the JVM already uses the hard limit
EMFILE: too many open files, watchNode dev servers, file watchersThe fd limit, or the inotify instance limit fs.inotify.max_user_instances (default 128)
Too many open files in systemAny program (ENFILE, error 23)The system-wide table is full, not one process
ulimit: open files: cannot modify limit: Operation not permittedbashYou asked for more than the hard limit; with ulimit -Sn the same request ends in Invalid argument. Shell limits

These are real lines from an nginx 1.22 error log, with addresses replaced and the second shortened:

Example output · /var/log/nginx/error.log
2026/10/10 06:46:05 [crit] 1132491#1132491: accept4() failed (24: Too many open files)
2026/10/10 06:46:05 [alert] 1132491#1132491: *3164090 socket() failed (24: Too many open files) while connecting to upstream, client: 192.0.2.120, server: example.com, request: "GET /static/css/app.css HTTP/1.1", upstream: "http://127.0.0.1:3001/static/css/app.css", host: "example.com"

Find the process that runs out

For a service, systemd shows the limits it hands out, and the running process shows what it really has. A program can change its own limit after starting, so trust /proc over the unit file:

Linux · a systemd service
systemctl show SERVICE -p LimitNOFILE -p LimitNOFILESoft
grep 'Max open files' /proc/$(systemctl show -p MainPID --value SERVICE)/limits
Example output · systemctl show nginx
LimitNOFILE=524288
LimitNOFILESoft=1024

When you do not know which process it is, list the ones holding the most descriptors:

Linux · top descriptor users (run as root)
for p in /proc/[0-9]*; do
  printf '%s %s %s\n' "$(ls "$p/fd" 2>/dev/null | wc -l)" "${p#/proc/}" "$(cat "$p/comm" 2>/dev/null)"
done | sort -rn | head

Count with /proc/PID/fd, not lsof -p PID | wc -l: lsof also lists memory-mapped libraries, the program binary and the working directory, which use no descriptor, so its count runs higher than the real one.

Why the limit is 1024, and who raises it alone

systemd starts every service with a soft limit of 1024 and a hard limit of 524288, which systemctl show -p DefaultLimitNOFILE -p DefaultLimitNOFILESoft confirms. The low soft limit protects old programs that use select(), which cannot handle descriptor numbers above 1023; the systemd documentation asks programs that do not use it to raise their own soft limit to the hard one. Some do:

  • Node.js raises it at start. Under prlimit --nofile=1024:524288 a Node process showed 524288 for both in our test, Python 1024.
  • Java does the same through the JVM option MaxFDLimit, on by default, and Go programs since Go 1.19.
  • nginx, Python and many C daemons keep 1024 unless you configure more.

So a Python or nginx service hits the wall at about a thousand connections, while a Node or Java service under systemd only reports EMFILE after 524288 descriptors, which is almost always a leak, not load. A Python program can raise itself at start, which avoids touching the unit:

Python · raise the soft limit to the hard limit
import resource

soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
resource.setrlimit(resource.RLIMIT_NOFILE, (hard, hard))

Raise it for a systemd service: LimitNOFILE

Put the limit into a drop-in rather than the unit file itself, so a package update does not undo it. systemctl edit creates /etc/systemd/system/SERVICE.service.d/override.conf and reloads systemd when you save:

Debian · Ubuntu
sudo systemctl edit SERVICE
the drop-in
[Service]
LimitNOFILE=65535
apply and check
sudo systemctl restart SERVICE
systemctl show SERVICE -p LimitNOFILE -p LimitNOFILESoft
grep 'Max open files' /proc/$(systemctl show -p MainPID --value SERVICE)/limits

One number sets soft and hard limit alike; LimitNOFILE=8192:65535 sets them separately. Limits apply when a process starts, so a reload is not enough; restart the service. If you write the drop-in by hand, run sudo systemctl daemon-reload first and check the unit with systemd-analyze verify SERVICE.service. It catches the classic mistake of a comment on the same line, which systemd ignores together with the value, leaving the old limit in place:

Example output · systemd-analyze verify
/etc/systemd/system/myapp.service.d/limits.conf:2: Failed to parse resource value, ignoring: 65535 # comment

DefaultLimitNOFILE= in /etc/systemd/system.conf would change the default for every service at once; a drop-in per service is easier to see and to undo. More on drop-ins is in changing a systemd unit safely.

nginx: worker_rlimit_nofile and worker_connections

nginx needs no systemd override. worker_rlimit_nofile sets the limit of each worker, which applies it while still running as root, before switching to www-data. Both directives go into /etc/nginx/nginx.conf, outside the http block:

nginx · /etc/nginx/nginx.conf, main context
worker_rlimit_nofile 16384;

events {
    worker_connections 4096;
}
apply and check
sudo nginx -t && sudo systemctl reload nginx
for p in $(pgrep -f 'nginx: worker'); do grep 'Max open files' /proc/$p/limits; done

worker_connections counts every connection of a worker, client and upstream alike, so a proxied request takes two slots, and each slot is a descriptor. Open files, temporary files and logs need descriptors on top, so keep worker_rlimit_nofile at least twice worker_connections. Debian and Ubuntu ship worker_connections 768 under the 1024 limit from systemd, so a stock nginx runs out of slots first. The file limit bites once worker_connections is raised above it without worker_rlimit_nofile: nginx warns at start and then logs accept4() failed (24: Too many open files) under load. A reload is enough, because the new workers set the new limit. Placed inside http, the directive fails nginx -t with "worker_rlimit_nofile" directive is not allowed here.

Shell, SSH logins and cron: ulimit and limits.conf

bash
ulimit -n           # soft limit of this shell
ulimit -Hn          # hard limit
ulimit -Sn 65535    # raise the soft limit for this shell and what it starts

Keep the -S: without it, bash sets the soft and the hard limit together, and a normal user cannot raise a hard limit again once it is lowered. A normal user can raise the soft limit up to the hard limit. Asking for more prints ulimit: open files: cannot modify limit: Invalid argument with -S, and cannot modify limit: Operation not permitted without it, because bash then tries to raise the hard limit too. For logins, set limits in a file under /etc/security/limits.d/, which pam_limits applies to SSH, su and sudo sessions and, on Debian, to cron jobs. It takes effect at the next login:

/etc/security/limits.d/90-nofile.conf
deploy  soft  nofile  65535
deploy  hard  nofile  65535
root    soft  nofile  65535
root    hard  nofile  65535

For a process that is failing right now, prlimit raises the limit of the running process without a restart. It lasts until the process ends, so make the permanent change as well:

Linux
sudo prlimit --pid PID --nofile=65535:65535
sudo prlimit --pid PID --nofile

Docker containers

A container does not read the host’s limits.conf; without a setting it inherits the Docker daemon’s defaults. Set it per container with docker run --ulimit nofile=65535:65535 or in Compose:

compose.yaml
services:
  app:
    image: myimage
    ulimits:
      nofile:
        soft: 65535
        hard: 65535

System-wide limits: fs.file-max and fs.nr_open

Linux
cat /proc/sys/fs/file-nr      # open handles, 0, maximum
cat /proc/sys/fs/nr_open      # ceiling for any per-process limit

Too many open files in system (ENFILE) means the kernel’s global table fs.file-max is full, not one process. On a current systemd distribution that is rare: on our Debian 12 test host fs.file-max reads 9223372036854775807, because systemd raises it at boot. fs.nr_open stays at 1048576 there and caps every per-process limit, including LimitNOFILE; raise it with a file in /etc/sysctl.d/ only if you truly need more than a million descriptors in one process. These are kernel settings: on a container-based VPS they usually cannot be changed from inside, on a KVM server they can (KVM vs OpenVZ).

Leak or load? Watch the count

Raising the limit fixes load. It only postpones a leak: a process that opens descriptors and never closes them hits 65535 next week instead of 1024 today. Watch the count for a while; under steady traffic it should level off.

Linux · run as root
# Count every 10 seconds; with a leak it keeps going up
watch -n 10 'ls /proc/PID/fd | wc -l'

# What kind of descriptors: sockets, pipes, files?
ls -l /proc/PID/fd | awk 'NR>1 {print $NF}' | sed -E 's/:\[[0-9]+\]$//' | sort | uniq -c | sort -rn | head

# Sockets the other side already closed, but the program never did
ss -tanp state close-wait | grep -o 'users:(("[^"]*"' | sort | uniq -c | sort -rn
  • Thousands of sockets in CLOSE_WAIT: the peer hung up and the application never called close(). That is a bug in the app or a library, often an HTTP or database client whose connections or responses are never closed.
  • The same file path many times: code that opens a file per request and relies on garbage collection to close it.
  • Entries ending in (deleted): files removed from disk but held open, typically rotated logs. They also keep using disk space, a cause of No space left on device that du cannot see.

One more Node.js detail from our test: a Node server at its limit does not crash or log anything. It accepts new connections and closes them at once, so curl reports Recv failure: Connection reset by peer, and nginx in front answers with a 502 Bad Gateway. Check the descriptor count before you go looking for a crash. If the process instead disappears with exit code 137, it ran out of memory, not descriptors: see OOM killed.

Frequently asked

How do I permanently increase the open file limit on Linux?

Set it where the process is started. For a systemd service, run 'sudo systemctl edit SERVICE', add LimitNOFILE=65535 under [Service] and restart the service. For nginx, set worker_rlimit_nofile in nginx.conf and reload. For SSH logins, su, sudo and cron, add soft and hard nofile lines to a file in /etc/security/limits.d/. For a container, use docker run --ulimit or ulimits in Compose.

Why does ulimit -n still show 1024 after I edited limits.conf?

limits.conf is applied by pam_limits when a session starts, so it only shows up in a new login, not in the shell you already have open. Lines with * do not apply to root, which needs lines of its own. And systemd services never read limits.conf at all: they get their limit from LimitNOFILE in the unit or a drop-in.

What is the difference between EMFILE and ENFILE?

EMFILE, error 24 'Too many open files', means one process reached its own RLIMIT_NOFILE limit; raise that limit or fix a leak in that process. ENFILE, error 23 'Too many open files in system', means the kernel-wide table fs.file-max is full. On current Debian systems systemd raises fs.file-max to a huge value at boot, so EMFILE is the one you meet.

Related articles

All troubleshooting