| Tested on | Red Hat Enterprise Linux 10.2 (lab VM) |
|---|---|
| Package | bash 5.2.26pam 1.6.1 (pam_limits)util-linux 2.40.2 (prlimit) |
| Applies to | RHEL, Rocky Linux, AlmaLinux, Fedora, Debian, Ubuntu, and other GNU/Linux systems with Bash and PAM |
| Privilege | Normal user for checks and soft-limit changes within hard limits; root or sudo for limits.d, hard-limit raises, and systemd units |
| Scope | Check shell limits with ulimit, raise open-file limits temporarily, persist login limits in limits.d, set systemd LimitNOFILE, and inspect limits on running processes with /proc and prlimit |
| Related guides | systemctl command su command nice and renice SSH command chgrp command |
ulimit is a shell builtin that shows or changes resource limits for
the current shell and the processes it starts. Limits apply to processes
and are inherited by child processes — they are not global kernel
tunables. Use ulimit for quick checks and temporary changes in an
interactive session; use /etc/security/limits.d/ for persistent login
limits and systemd Limit* directives for services.
Quick reference: ulimit commands
| Task | Command |
|---|---|
| All limits (current shell) | ulimit -a |
| Soft limits only | ulimit -Sa |
| Hard limits only | ulimit -Ha |
| Open files (effective) | ulimit -n |
| Open files soft / hard | ulimit -Sn / ulimit -Hn |
| Max user processes | ulimit -u |
| Stack size (KB) | ulimit -s |
| Raise open files (session) | ulimit -Sn 4096 |
| Limits on a PID | prlimit --pid PID --nofile |
| Service file limit | systemctl show unit -p LimitNOFILE |
1. What does ulimit do in Linux?
Linux tracks per-process limits such as open file descriptors, stack
size, and maximum user processes. The ulimit command is implemented as
a shell builtin in Bash (and similar shells), not as a separate
binary. It adjusts limits for the current shell session; child commands
and scripts started from that shell inherit those values.
ulimit is the right tool when you are debugging an interactive login,
an SSH session, or a script run from your shell. It does not change
limits for an already-running daemon started by systemd, and it does not
replace /etc/security/limits.d/ for permanent per-user login policy.
2. Check current ulimit values
List every limit for the current shell:
ulimit -areal-time non-blocking time (microseconds, -R) unlimited
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 22995
max locked memory (kbytes, -l) 8192
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 22995
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimitedThe open files line (-n) is the limit most often hit on busy
servers. Values vary by distribution, PAM defaults, and whether you are
root or a normal user.
Query individual limits when you already know which one matters:
ulimit -n1024Max user processes (-u):
ulimit -u22995Stack size in kilobytes (-s):
ulimit -s8192Core dump size (-c):
ulimit -cunlimitedLocked memory in kilobytes (-l):
ulimit -l8192| Option | Limit | Typical use |
|---|---|---|
-n |
Open file descriptors | Web servers, databases, many connections |
-u |
Max user processes | Fork-heavy apps, thread pools |
-s |
Stack size (KB) | Deep recursion, some runtimes |
-c |
Core file size | Crash dumps |
-l |
Locked memory (KB) | Databases, RDMA, mlock |
Run ulimit --help in Bash for the full option list; this guide focuses
on the limits administrators change most often.
3. Soft vs hard ulimit
Each resource has two ceilings:
- Soft limit — enforced now for the process
- Hard limit — ceiling for the soft limit. An unprivileged process can lower its hard limit but cannot raise it again; raising it requires sufficient privilege
Read both for open files:
ulimit -Sn1024The hard ceiling for the same resource:
ulimit -Hn524288A normal user can raise the soft open-file limit up to the hard limit for the current shell session:
ulimit -Sn 4096Confirm the new effective value:
ulimit -n4096You cannot set soft above hard, and a non-root user cannot raise the
hard limit with ulimit:
ulimit -Hn 20000-bash: ulimit: open files: cannot modify limit: Operation not permittedPersistent hard limits for login sessions can be supplied through
pam_limits; systemd services use their own Limit* settings. The
rule in one line: soft limit ≤ hard limit.
4. Fix "Too many open files" with ulimit -n
Open-file exhaustion (Too many open files) is the most common production
ulimit problem. Inspect soft and hard before you change anything:
ulimit -Sn1024Read the hard open-files ceiling:
ulimit -Hn524288Raise the soft limit for this shell session only:
ulimit -Sn 65535Confirm the effective value:
ulimit -n65535This lasts until the shell exits. Set the higher limit in the same shell before starting a long-running program; the child process inherits that resource limit.
If 65535 exceeds your hard limit, lower the target or raise the hard
limit through limits.d or systemd instead.
5. Set ulimit permanently with limits.conf / limits.d
Session ulimit changes disappear when you log out. For login users,
rules in /etc/security/limits.conf and /etc/security/limits.d/*.conf
are applied only when the relevant PAM session stack includes
pam_limits.so.
Prefer a drop-in file under limits.d rather than editing limits.conf
directly:
/etc/security/limits.d/90-app-limits.conf
appuser soft nofile 65535
appuser hard nofile 65535
appuser soft nproc 4096
appuser hard nproc 4096Apply the same limits to every member of a group with @:
@developers soft nofile 65535
@developers hard nofile 65535After you add or edit a file, start a new login session — open a fresh
SSH connection or su - username — then verify:
ulimit -Sn65535Hard limit from the same limits.d entry:
ulimit -Hn65535A reboot is not required. Limits attach when PAM opens the session (with
pam_limits in the stack), not when the file is saved.
On Linux 2.4.30 and later, the legacy rss (maximum resident set size)
limit in limits.conf is ignored — do not rely on rss entries for
modern kernels.
6. Why limits.conf does not change a systemd service
limits.d affects PAM login sessions (SSH, console login, su -)
when pam_limits.so runs. systemd-managed service processes do not
normally obtain their resource limits from PAM limits.conf /
limits.d; configure the service with systemd Limit* directives
instead.
/etc/security/limits.d/*.conf → PAM login session → user shell
systemd unit file → systemd exec → daemon processFor a service such as nginx or sshd, set limits in the unit or a
drop-in:
sudo systemctl edit nginx.service[Service]
LimitNOFILE=65535Reload systemd and restart the service after you save the drop-in. Inspect what systemd applied:
systemctl show sshd -p LimitNOFILELimitNOFILE=524288Related directives on the [Service] section include LimitNOFILE,
LimitNPROC, LimitCORE, and LimitMEMLOCK. LimitNPROC= is counted
by real UID and can affect multiple processes for the same user; use
TasksMax= when you need a service-scoped task limit. See
systemd.exec(5) for the full list; this guide does not replace a
systemd resource-tuning chapter.
7. Check resource limits for a running process
ulimit in your shell describes your shell, not necessarily a
background daemon started earlier by systemd.
Read limits from the kernel for a specific PID:
cat /proc/$$/limitsLimit Soft Limit Hard Limit Units
Max cpu time unlimited unlimited seconds
Max file size unlimited unlimited bytes
Max data size unlimited unlimited bytes
Max stack size 8388608 unlimited bytes
Max core file size unlimited unlimited bytes
Max resident set unlimited unlimited bytes
Max processes 22995 22995 processes
Max open files 524288 524288 files
Max locked memory 8388608 8388608 bytes
Max address space unlimited unlimited bytes
Max file locks unlimited unlimited locks$$ is the current shell PID. Replace it with the application PID when
you troubleshoot a service.
prlimit from util-linux prints the same data in a compact form:
prlimit --pid $$ --nofileRESOURCE DESCRIPTION SOFT HARD UNITS
NOFILE max number of open files 524288 524288 filesCompare shell ulimit -n with prlimit on the service PID when logs
still report too many open files — the daemon often has a different limit
than your interactive session.
8. Common ulimit errors and problems
| Problem | Check |
|---|---|
ulimit -n change fails |
Compare soft to hard with ulimit -Sn and ulimit -Hn; soft cannot exceed hard |
Operation not permitted on ulimit -H |
Normal users cannot raise hard limits — use limits.d or systemd |
limits.conf change not visible |
Open a new login session; confirm pam_limits.so is in the session PAM stack |
limits.conf does not affect a service |
systemd-managed processes use unit LimitNOFILE= (not PAM limits.d) |
| Application still reports too many open files | Inspect cat /proc/PID/limits or prlimit --pid PID --nofile |
ulimit differs between users |
Compare /etc/security/limits.d/ entries and group rules (@group) |
| Shell limit differs from service | Login PAM path vs systemd Limit* — they are separate mechanisms |
Summary
Use ulimit -a and ulimit -n to see what your shell enforces today.
Soft limits are the active ceiling; hard limits are the ceiling for soft
limits. An unprivileged process may lower its hard limit but cannot raise
it again; raising a hard limit requires sufficient privilege. For the common open-files case, ulimit -Sn
followed by verification with ulimit -n fixes a session temporarily;
/etc/security/limits.d/ makes per-user or per-group limits persist
across logins when pam_limits.so runs in the session stack.
systemd-managed service processes do not normally obtain limits from PAM
limits.conf / limits.d — set LimitNOFILE and related directives on
the unit, then confirm with systemctl show. When logs still disagree
with your shell, check the real process with /proc/PID/limits or
prlimit. For service management context, see
systemctl command.
References
- Bash builtin ulimit — shell options and modifiers
- getrlimit(2) — kernel resource limit API
- prlimit(1) — view and change limits on a running process
- limits.conf(5) — PAM limits file format
- pam_limits(8) — PAM module for login limits
- systemd.exec(5) —
LimitNOFILE,LimitNPROC, and related directives

