Linux: Too many open files (EMFILE)
Hi, it's BlueByte. If a service starts throwing EMFILE under load, there are really two questions hiding in one error: is the limit too low, or is something leaking? Let's tell those apart first — because raising the limit fixes one and only postpones the other — then apply the fix where the process actually runs.
What EMFILE is telling you
A server or script starts failing under load:
Error: EMFILE: too many open filesThe process tried to open a file, socket, or connection past the maximum number of file descriptors it is allowed. Every socket and pipe counts, so a busy network service hits this well before it runs out of actual files. The failure is per-process, and the fix has to be applied where that process runs — which is where people most often get it wrong.
Too low, or leaking? — the two real causes
Each process has a soft limit on open descriptors — often 1024 by default. Once it is reached, every new open(), socket(), or accept() fails with EMFILE. Two underlying situations need different responses:
- The limit is genuinely too low for the workload — a proxy or database handling thousands of concurrent connections needs far more than 1024.
- The process is leaking descriptors — opening connections or files it never closes, so the count only grows until it hits the ceiling.
Telling these apart is the whole game.
Watch the descriptor count to tell them apart
You do not have to guess which one it is — watch it. Check the current limit and how many the process holds right now:
ulimit -n
ls /proc/$(pgrep -f myservice)/fd | wc -lThen watch that second number over a few minutes of steady traffic. If it climbs and never drops, you have a leak. If it plateaus near the limit under real load, the limit is simply too low. To see the effective limit on the running process itself — not your shell — read its limits file:
grep "open files" /proc/$(pgrep -f myservice)/limitsRaise the limit where the process runs
- For a service, raise the limit where it runs. A systemd unit ignores your shell's
ulimit, so set it in the unit:
# /etc/systemd/system/myservice.service
[Service]
LimitNOFILE=65536sudo systemctl daemon-reload
sudo systemctl restart myservice- For login sessions, add limits in
/etc/security/limits.conf, then open a new session:
* soft nofile 65536
* hard nofile 65536- If you found a leak, fix the code that opens without closing — the limit change only buys time.
A real case: a leak, not a low limit
A Node service starts throwing EMFILE after about an hour of traffic. ls /proc/<pid>/fd | wc -l reads 1024 and stays pinned there; watched over ten minutes on a previous run it climbed steadily and never fell. That is a leak signature, not a low limit — the app opens an HTTP client per request and never closes it. You fix the client to reuse a pooled connection, and the descriptor count now plateaus around 200 under the same load. You still raise LimitNOFILE to 65536 for headroom, but the leak fix is what actually stopped the failure.
Confirm the limit applies to the process, not your shell
This is the step people skip, so check it directly:
cat /proc/$(pgrep -f myservice)/limits | grep "open files"The "Max open files" column should show the value you set. Then run the load that used to fail, confirm it no longer does, and that the descriptor count is stable.
Keep it from recurring
Set LimitNOFILE deliberately for network services as part of their unit file, match it to real concurrency plus headroom, and add a metric or alert on descriptor count so a slow leak is visible long before it takes the service down.
How this differs from ENFILE
EMFILE is per-process; ENFILE ("file table overflow") is the whole system running out — much rarer, and fixed with the kernel-wide fs.file-max sysctl. A Too many open files from a shell doing ulimit work is the same limit but reached interactively. When you hit EMFILE, watch the count before you raise anything — the graph tells you which problem you actually have.
Related questions
I ran ulimit -n 65536 but the service still fails.
A systemd service does not inherit your shell's ulimit. Set LimitNOFILE in the unit file and reload systemd.
What value should I set?
Match it to real concurrency plus headroom. 65536 is a common, safe ceiling for a busy network service; do not set it to unlimited without knowing why.
How do I know it's a leak and not just a low limit?
Watch ls /proc/<pid>/fd | wc -l over time. Under steady traffic a healthy process plateaus; a leaking one climbs without falling back.
Does this count network sockets?
Yes. Sockets, pipes, and epoll instances all consume file descriptors, which is why network services hit EMFILE long before they open that many real files.
The whole system is out of files, not one process.
That is ENFILE, not EMFILE. Raise the kernel-wide limit with sysctl fs.file-max, but first check whether one runaway process is consuming them all.
References
Haneul Seo
Infrastructure engineer · 10+ years running Linux fleets
More in this category
systemd: Start request repeated too quickly
systemd refuses to start a unit that was started more than StartLimitBurst times (default 5) within StartLimitIntervalSec (default 10s), and Restart= counts against that limit. With the 100 ms default RestartSec a crashing service burns all five attempts in under a second. Find the real crash in the journal, fix it, run reset-failed, and give restarts room with RestartSec.
SSH: Received disconnect ... Too many authentication failures
Your agent is offering more keys than the server will let you try. Every public key sshd looks at burns one of the MaxAuthTries attempts — six by default, often three on a hardened host — so the right key never gets its turn and the server hangs up before you type anything. IdentitiesOnly=yes with an explicit IdentityFile pins the connection to one key and the attempt count drops to one.
Active Directory: replication fails with error 1722, The RPC server is unavailable
RPC reports 1722 (0x6ba, RPC_S_SERVER_UNAVAILABLE) when a lower layer fails to connect, so the real fault is almost never RPC itself — it is DNS, a blocked port, or a host-side setting on one of the two domain controllers. repadmin tells you which partner is failing, dcdiag /test:dns rules out name resolution, and Test-NetConnection plus the dynamic port range settle the firewall question. The most common miss is a rule that allows TCP 135 but not 49152–65535.
Windows Server RDS: The remote session was disconnected because there are no Remote Desktop License Servers available to provide a license
The 120-day RD Licensing grace period ended and the session host has no usable license server, so it refuses sessions. GetGracePeriodDays returning DaysLeft 0 and an empty SpecifiedLSList confirm it in seconds. The fix is a real, activated license server with CALs that are new enough for the host — a 2019 CAL cannot serve a 2022 session host — configured through the deployment or the Licensing policies, plus RPC ports open between the two.
Windows 11: "Your organization's security policies block unauthenticated guest access" when opening a NAS share (0x80070035)
The SMB client on Windows 10 Enterprise/Education/Pro for Workstations, Windows 11 Pro and Windows Server 2019+ refuses guest logons by default, and Windows 11 24H2 Enterprise/Pro/Education also requires SMB signing, which guest sessions can't do. A NAS share that only offers guest access therefore fails with the 'block unauthenticated guest access' dialog, Error code 0x80070035, or System error 3227320323, and Event ID 31017 'Rejected an insecure guest logon' lands in the SmbClient/Security log. The fix Microsoft recommends is a real account on the NAS and signing support in its firmware; Set-SmbClientConfiguration -EnableInsecureGuestLogons $true (plus -RequireSecuritySignature $false on 24H2) is the escape hatch, and it costs you signing and encryption on that client.
Ubuntu/Debian: E: Could not get lock /var/lib/dpkg/lock-frontend — who holds it and how to wait for it
Another package manager, usually Ubuntu's unattended-upgrades fired by a persistent systemd timer at boot, holds the dpkg frontend lock while your apt-get runs. apt-get gives up at once while apt waits because Ubuntu ships binary::apt::DPkg::Lock::Timeout "120" for the apt binary only. Read the PID from the message, let the run finish or pass -o DPkg::Lock::Timeout=<seconds> to apt-get, run dpkg --configure -a only after a genuinely interrupted run, and never delete the lock file: it is an fcntl lock the kernel releases when the holder exits.