Fix "Too Many Open Files" on Linux (ulimit)
When a process hits its file descriptor ceiling everything breaks at once; here is how to find the real limit and raise it correctly.
Key takeaways
- Too many open files (EMFILE) means a process hit its per-process file descriptor limit, often the 1024 soft default.
- Read the live limit in /proc/PID/limits, count fds with ls /proc/PID/fd | wc -l, then raise it where the process starts: LimitNOFILE= for systemd services, limits.conf for PAM logins, ulimit -n for shells.
On this page
"Too many open files" (EMFILE) means one process hit its file-descriptor limit, usually the 1024 soft default. Check the live value with grep "open files" /proc/PID/limits, count usage with ls /proc/PID/fd | wc -l, then raise it where the process starts: LimitNOFILE= for systemd services, limits.conf for login sessions, ulimit -n for a shell.
The symptom: logs fill with accept: too many open files, new connections hang, and the health check flaps. Every socket, pipe, epoll instance, and open file counts against the limit, and the limit is per-process, so knowing how to track per-process resource usage (see process management and monitoring in depth) decides where you fix it.
What the error actually means
A file descriptor (fd) is a small integer the kernel hands back for anything openable. The soft limit RLIMIT_NOFILE caps how many a single process may hold at once. Cross it and open(), socket(), or accept() fail with EMFILE. You will see it as Too many open files in strace, application logs, or a Java java.net.SocketException.
Two limits exist per process. The soft limit is the enforced value. The hard limit is the ceiling an unprivileged process may raise its own soft limit to; only a process with CAP_SYS_RESOURCE can raise the hard limit.
See the current limits
$ ulimit -Sn # soft
1024
$ ulimit -Hn # hard
524288
ulimit reports the limits of your current shell. It does not tell you what a running daemon inherited. The daemon may have been started by systemd, cron, or an init script with a completely different environment. Read its actual limits from procfs:
$ cat /proc/$(pgrep -o nginx)/limits | grep -i "open files"
Max open files 1024 4096 files
That first column is the soft limit the process is really running with. If it says 1024 while your shell says 524288, your shell config is irrelevant to that process.
Count how many fds a process is holding
$ ls /proc/12345/fd | wc -l
1017
At 1017 against a soft limit of 1024 you are about to fall over. To see what those fds are, lsof is the readable view:
$ lsof -p 12345 | awk '{print $5}' | sort | uniq -c | sort -rn
880 IPv4
71 REG
12 unix
8 DIR
5 CHR
880 open IPv4 sockets on a process that should hold a few dozen is a leak signature, not a limit that is too low. Hold that thought.
Raise the limit the right way, per context
There is no single place to change this. Where you edit depends on how the process starts.
Interactive shell or a script you launch by hand: ulimit -n 65536 in that shell, before starting the program. It applies to that shell and its children only, and it cannot exceed the hard limit.
Login sessions (SSH, su, getty): edit /etc/security/limits.conf and rely on pam_limits. This path only affects processes started through PAM.
# /etc/security/limits.conf
appuser soft nofile 65536
appuser hard nofile 131072
Confirm pam_limits.so is present in the relevant PAM stack (/etc/pam.d/common-session or /etc/pam.d/sshd), then log out and back in. A common trap: editing limits.conf and expecting a systemd-managed service to pick it up. It will not. PAM is not in that path.
systemd services: set it in the unit, not in limits.conf. systemd ignores pam_limits for services it starts.
# /etc/systemd/system/myapp.service (or a drop-in)
[Service]
LimitNOFILE=65536
Use a drop-in to avoid editing packaged units:
$ sudo systemctl edit myapp
# add the [Service] block above, then:
$ sudo systemctl daemon-reload
$ sudo systemctl restart myapp
daemon-reload alone does not change a running process. The service must restart to inherit the new limit.
The system-wide ceiling
Per-process limits sit under two kernel-wide sysctls. fs.file-max is the total number of open file handles the whole system will allow. fs.nr_open is the maximum any single process limit may be set to, so a LimitNOFILE higher than fs.nr_open is silently clamped.
$ sysctl fs.file-max fs.nr_open
fs.file-max = 9223372036854775807
fs.nr_open = 1048576
When file-max is exhausted the error is ENFILE ("Too many open files in system"), not EMFILE. On many current distros it reads as the 64-bit maximum shown above, so you rarely touch it. If you genuinely need per-process limits above ~1M, raise fs.nr_open first in /etc/sysctl.d/, then set the higher LimitNOFILE.
Verify it actually applied
Do not trust the config file. Trust procfs on the live PID after restart:
$ systemctl show myapp -p MainPID --value
12345
$ grep "open files" /proc/12345/limits
Max open files 65536 65536 files
If that still reads 1024, you edited the wrong place for how the process starts. That mismatch is the single most common reason this error "won't go away."
Root cause vs bandaid
Raising the limit is correct when the workload legitimately needs more fds: a busy reverse proxy, a database with many connections. It is a bandaid when the fd count climbs without bound and never plateaus. Common leak sources:
- Connection pools: a pool with no max, or code that opens a client per request and never closes it. The fix is in the pool config, not the kernel.
- Unclosed files or sockets: a missing
close()in an error path. Watch/proc/<pid>/fdover time; steady growth under steady load means a leak. - inotify watches: watchers count against
fs.inotify.max_user_watches, a separate limit. A tool watching a huge tree throwsENOSPC("no space left on device") rather than EMFILE, but it is the same class of exhaustion. Raise it withsysctl fs.inotify.max_user_watches=524288if the watch count is real.
If you raise ulimit and the process refills the new headroom in an hour, you bought an hour. Sample the fd count over time before deciding.
This is one entry in the broader Linux troubleshooting guide; the same procfs-first instinct applies when you hit address already in use.
Questions people ask
What does "accept: too many open files" mean?
A listening server called accept() for a new connection and the kernel refused, because the process already holds as many descriptors as its RLIMIT_NOFILE soft limit allows. Each accepted connection is a new fd, so busy servers hit this first. Raise LimitNOFILE= if the load is real; if the fd count keeps growing under steady traffic, connections are not being closed.
Why doesn't editing limits.conf fix my systemd service?
/etc/security/limits.conf is applied by pam_limits, and only processes started through a PAM session (SSH, su, console login) pass through PAM. systemd services do not. As of October 2026 they get systemd's default of 1024 soft and 524288 hard (DefaultLimitNOFILE=1024:524288) unless the unit sets LimitNOFILE=. Add it in a drop-in, daemon-reload, and restart the service.
What is a safe value for LimitNOFILE?
For a busy proxy or database, 65536 is a common, safe starting point; it stays far under the kernel ceiling fs.nr_open (1048576 by default). Keep the soft limit at 1024 for programs that still use select(2), which cannot handle descriptor numbers above 1023. Size it from measured peak usage plus headroom, not from the largest number that works.
The fix in order
- Read
/proc/<pid>/limitson the actual running process. Ignore your shell'sulimit. - Count fds with
ls /proc/<pid>/fd | wc -land break them down withlsof -p. Decide leak vs legitimate load. - If it is real load, set the limit where the process starts:
LimitNOFILE=for systemd, limits.conf for PAM logins,ulimit -nfor hand-run scripts. - Restart the process and re-check
/proc/<pid>/limits. Config that is not reflected on the live PID did nothing. - If it is a leak, fix the pool or the missing close. The kernel limit is a fuse, not a solution.
The call we would make on a paging alert: read the live limits, count the fds, and only reach for the config file once lsof proves the process needs the headroom rather than losing it.
Sources
Best LLM APIs and AI Infrastructure in 2026 — A Cost and Capability Map
The LLM stack is a maze of APIs, GPU clouds, gateways, and serving tools. This is the map to what each layer is for and how to keep the bill sane.
CircleCI Best Practices in 2026: Fast, Safe Pipelines
A production-focused CircleCI guide: orbs, reusable commands and executors, workflows with fan-in/fan-out, contexts and OIDC for secrets, layered caching, test splitting, approval jobs, and dynamic config — with copy-paste examples.
More from Linux
Explore more articles in this category
CERN Left Red Hat for Debian: The CPU Baseline Lesson
CERN is moving accelerator control computers to Debian because RHEL raised its minimum CPU level. Check your own fleet's x86-64-vN support before the next OS upgrade does it for you.
ext4 vs XFS vs Btrfs: Choosing a Filesystem for a Server
The default filesystem your distro picks is not always the right one for your workload. Here is what actually differs and when each one wins.
journald Log Management: Retention, Filtering, and Forwarding
journald is the default log sink on every systemd distro, and most of it runs on defaults nobody chose. Here is how to actually control it.
You might have missed
Evergreen posts worth revisiting.