Why do I get “too many open files” and zombie processes?
Find the process leaking file descriptors with ss and lsof, then raise the limit with ulimit and make it persist across logins.
What this covers
“Too many open files” and zombie processes usually travel together, because both come from one misbehaving service: it opens descriptors without closing them and spawns children without reaping them. That is why blindly raising the limit only buys time. This guide walks you from identifying the offending process to raising the ceiling, and then to making the change permanent so it is still there after the next reboot or login.
Symptom
See which process is holding all the sockets
Start by counting instead of guessing. The socket view lists every listening and established TCP/UDP endpoint together with the process that owns it, so a service sitting on hundreds of connections stands out immediately. That pattern points at one program leaking file descriptors, which is a very different problem from a machine-wide shortage. You are done with this step when you can name the single process responsible for most of the sockets, and you have its PID written down.
See which services listen on which ports and who is connected — the modern netstat replacement.
$ sudo ss -tulpnConfirm a descriptor leak with open-but-deleted files
A process that opens a file, unlinks it and never closes it keeps that descriptor alive forever — the file shows up with a link count of zero. If the same PID keeps appearing in this list, you have found a genuine leak rather than a limit that is simply set too low, and raising the ceiling would only postpone the failure. Expect a password prompt: inspecting another user's descriptors needs root.
When df says full but du disagrees, open-but-deleted files are the usual culprit; lsof +L1 lists them with the process holding each.
$ sudo lsof +L1Raise the descriptor ceiling in the shell that starts the service
A process inherits its limit from the shell that forks it, so the change has to be made in that shell before the service starts. Use the shell built-in that reads and writes the limit — setting it to a larger number removes the immediate 'too many open files' errors for anything launched afterwards. Print the value again in the same session to confirm it stuck; a higher number than before means the step worked, and it will be lost the moment you log out.
ulimit -n shows or changes the file-descriptor limit of the current shell, fixing 'Too many open files' errors for servers started from that shell.
$ ulimit -n 4096▾ Undo
$ ulimit -n 1024Make the new limit survive a logout
The value you just set disappears with the shell. Editing the PAM limits file in place gives every new login session the higher ceiling, which is what you want on a server. Because an in-place edit writes straight to the file, keep a backup copy first so a typo does not lock you out of logging in. Confirm by opening a completely new session and printing the limit there; still remember that an already-running service must be restarted to pick it up.
Apply search-and-replace across one or many files on Linux with sed -i, keeping backups with -i.bak.
$ sed -i 's/old-domain.com/new-domain.com/g' *.conf▾ Undo
$ git checkout -- *.conf (or restore from the .bak created by sed -i.bak)How to confirm it worked
Re-run the socket listing after the change and watch the offending process: its connection count stays below the new ceiling and stops climbing. New logins report the higher limit, the error stops appearing in the log, and the zombie entries disappear once their parent process has been restarted.
Undo everything
Every command above can be reverted. Run these in order to undo all of it.
$ git checkout -- *.conf (or restore from the .bak created by sed -i.bak)
ulimit -n 1024Review before running — some steps may not be independent.
Sources
- lsof(8) - Linux manual pageEvidence: The +L1 option selects files with a link count less than one, i.e. open files that have been unlinked (deleted).
- Sed — ArchWikiEvidence: Examples of GNU sed -i in-place editing and -i.bak backup extension usage
- getrlimit(2)/setrlimit(2) - get/set resource limitsEvidence: RLIMIT_NOFILE specifies a value one greater than the maximum file descriptor number that can be opened by this process; limits have a soft value (enforced) and a hard value (ceiling for the soft).
- ss(8) — Arch Manual PagesEvidence: Same options documented for ss, another utility to investigate sockets.
- ss(8) — Debian bookwormEvidence: Documents -t/--tcp, -u/--udp, -l/--listening, -p/--processes and -n/--numeric for the socket statistics tool.
- sed(1P) — POSIX manual pageEvidence: Documents the s/re/replacement/flags substitution, /g global flag, and address ranges
Last verified: 2026-09-22
Related guides
A practical checklist for finding which ports are open on a Linux machine or across your network, from local sockets to a full nmap scan.
Unmount fails because a process still has a file open on that filesystem. Find the holder, stop it, then unmount cleanly.
A problem-fix walkthrough for a full Linux disk: find the culprit filesystem, remove space hogs, sweep caches, and verify the space came back.