ulimit: Understanding Resource Limits
What Is ulimit?
Conclusion:
ulimitshows and changes the upper bounds on resources (open files, processes, memory, and more) that a shell and the processes it launches may use.
ulimit is a shell builtin (in bash and similar shells) that calls the kernel's getrlimit(2) / setrlimit(2) to read and set resource limits. A limit applies per process and is inherited by child processes created with fork.
The three common reasons to reach for it:
- Diagnosing limit-exhaustion errors such as "Too many open files"
- Raising limits so databases and web servers can handle their concurrency
- Lowering limits to keep a runaway script from exhausting resources
Assumptions
- bash is assumed (
ulimitis a shell builtin; other shells like zsh support it with slightly different flags) - The persistence section assumes a systemd-based distro (Ubuntu / RHEL family)
Soft Limits vs Hard Limits
Conclusion: The soft limit is what is actually enforced; the hard limit is the ceiling for the soft limit. An unprivileged user can raise the soft limit up to the hard limit, but only root can raise the hard limit.
Every resource has two values.
| Type | Meaning | What an unprivileged user can do |
|---|---|---|
| soft | The currently enforced limit | Raise or lower it, up to the hard limit |
| hard | The ceiling the soft cannot exceed | Lower only (cannot raise it) |
Once you lower a hard limit, you cannot raise it again within that process tree (raising requires root, i.e. CAP_SYS_RESOURCE). In ulimit, flags select the target.
$ ulimit -Sn # show the soft open files limit $ ulimit -Hn # show the hard open files limit
-S: act on the soft limit-H: act on the hard limit- If omitted: display shows the soft value, but setting changes both at once — keep this in mind.
How Do I Check the Current Limits?
Conclusion:
ulimit -alists the current soft limit for every resource; use a single flag such as-nto inspect one resource.
$ ulimit -a
real-time non-blocking time (microseconds, -R) unlimited core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 15363 max locked memory (kbytes, -l) 8192 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 stack size (kbytes, -s) 8192 max user processes (-u) 15363 virtual memory (kbytes, -v) unlimited
-a prints soft values. To see all hard limits at once, use ulimit -aH.
$ ulimit -aH # hard limits for every resource
The Main Resource Types
Conclusion: In day-to-day work the four you touch most are
-n(open files),-u(processes),-c(core), and-s(stack).
| Flag | Resource | Typical use / symptom |
|---|---|---|
-n |
open files | "Too many open files." The file descriptor limit |
-u |
max user processes | "fork: retry: Resource temporarily unavailable" |
-c |
core file size | Whether a crash writes a core dump (0 disables it) |
-f |
file size | Maximum size of a single file |
-s |
stack size | Investigating segfaults from deep recursion |
-v |
virtual memory | Cap on the process's total virtual memory |
-l |
max locked memory | How much memory can be mlocked (relevant for DBs) |
-u (max user processes) limits the process count for the whole user, not just this shell. It looks per-shell but is counted across every process owned by the same UID.
How Do I Change a Limit Temporarily?
Conclusion: Running something like
ulimit -Sn 4096affects only the current shell and processes it starts afterward; closing the shell reverts it.
# Raise the soft open files limit to 4096 (within the hard limit) $ ulimit -Sn 4096 # Verify $ ulimit -Sn 4096
Asking for more than the hard limit is rejected.
$ ulimit -Sn 999999 bash: ulimit: open files: cannot modify limit: Operation not permitted
That requires raising the hard limit, which an unprivileged user cannot do. As root you can change both at once:
# root only. Set soft and hard together to 65536 $ sudo bash -c 'ulimit -n 65536; exec your-server'
A ulimit change reaches only the shell that ran it and its descendants. It does not change the limits of an already-running daemon. To apply limits to a live process, use prlimit.
How Do I Make a Limit Persistent?
Conclusion: For login sessions use
/etc/security/limits.d/*.conf; for systemd-managed services use the unit'sLimitNOFILE=. They are applied through different paths.
Login shells (via pam_limits)
/etc/security/limits.conf and /etc/security/limits.d/*.conf are applied at login by the PAM module pam_limits. This covers shells started through SSH login or login.
# /etc/security/limits.d/90-nofile.conf * soft nofile 8192 * hard nofile 65536 deploy soft nproc 4096
The format is <domain> <type> <item> <value>, where domain is a username, @groupname, or * for everyone. Changes take effect only after you log out and log back in.
pam_limits does not affect processes that do not go through a PAM session. limits.conf does not apply to daemons started by systemd, which is a common reason a "raised" limit appears to have no effect.
systemd services
For systemd-managed services, set the limit in the unit's [Service] section.
# /etc/systemd/system/myapp.service.d/override.conf [Service] LimitNOFILE=65536 LimitNPROC=4096
$ sudo systemctl daemon-reload $ sudo systemctl restart myapp
To change the default for all services, edit DefaultLimitNOFILE= in /etc/systemd/system.conf. Check the effective value with systemctl show myapp -p LimitNOFILE.
How Do I Inspect a Running Process's Limits?
Conclusion: Read
/proc/<PID>/limitsor useprlimit --pid <PID>.prlimitcan also change a running process's limits without a restart.
$ cat /proc/1234/limits
Limit Soft Limit Hard Limit Units Max open files 1024 524288 files Max processes 15363 15363 processes ...
prlimit checks and changes limits in one line.
# Inspect $ prlimit --pid 1234 --nofile # Change a running process's soft/hard to 8192 (may need privileges) $ sudo prlimit --pid 1234 --nofile=8192:8192 # Launch a command with a limit applied $ prlimit --nofile=4096:4096 ./myserver
Fixing "Too many open files"
Conclusion: Count the actual file descriptors with
lsofand compare them against the limit. Decide whether it is an FD leak or a genuinely insufficient limit before acting.
"Too many open files" means the open files (-n) limit was reached. Work through it as follows.
- Identify the PID of the affected process
- Check its effective limit (
cat /proc/<PID>/limits) - Count how many descriptors it currently has open
# Count the FDs a process has open $ lsof -p 1234 | wc -l
- If the count is pinned at the limit, decide the cause.
- FD leak (descriptors opened but never closed) → fixing the application is the real solution; raising the limit only buys time
- Legitimately high (heavy concurrency) → raise the limit using the persistence steps
Avoid blindly raising limits toward unlimited. It masks FD leaks and can turn into a different failure — memory exhaustion or hitting the kernel's file-max.
Summary
ulimitmanages per-process resource limits; keep the soft/hard two-tier model in mind- Change temporarily with
ulimit -Sn N; inspect withulimit -a,/proc/<PID>/limits, orprlimit - Persist via
limits.d/*.conffor logins, or the unit'sLimitNOFILE=for systemd services — do not mix up the paths - For "Too many open files," suspect an FD leak before raising the limit