Set and Check Process Limits with prlimit
prlimit shows you the ceilings the kernel puts on a process and lets you change them for one command without touching the whole service. This guide covers reading limits safely, testing a change on a disposable process, and starting a command with a limit already in place. The examples use the installed prlimit binary from util-linux 2.41.3; the local manpage documents util-linux 2.39.3, so the version on your PATH can drift from what the manpage describes. Budget fifteen minutes.
The route
Jump straight to the step you need, or tick off Done means at the end.
- You need: a shell and util-linux. Inspection is a plain user command.
- Watch for: changing another user's process, raising a hard limit, or touching a service's limits can need elevated privileges, and even
sudodoes not guarantee the kernel or the service policy will allow it.
1. Check the binary you are actually running
Two installs of util-linux on the same box can expose different option names, so confirm the executable and version before you trust any example, including this one:
$ command -v prlimit
/home/linuxbrew/.linuxbrew/bin/prlimit
$ prlimit --version
prlimit from util-linux 2.41.3
Your path and version can differ. Keep this check with a troubleshooting note or a script, because it explains why an option that works for you might not exist on someone else's box.
Checkpoint
Ask the installed binary for its own resource and output names before writing a script around it.
$ prlimit --help
Usage:
prlimit [options] [--<resource>=<limit>] [-p PID]
prlimit [options] [--<resource>=<limit>] COMMAND
Show or change the resource limits of a process.
The help output is the authority for the binary you are calling right now, not the manpage. Below, nofile means the maximum number of open file descriptors and cpu means CPU time in seconds.
2. Read the current shell's limits first
Point --pid at the shell's own process ID and you get a read-only report:
$ prlimit --pid $$ --noheadings --output RESOURCE,SOFT,HARD --nofile
NOFILE 1048576 1048576
- First number is the soft limit. That is what actually gets enforced day to day.
- Second number is the hard limit, the ceiling. A process can usually lower its own limits, but raising the hard one is restricted.
Drop --output and you get the full, human-readable table for every resource instead of one line:
$ prlimit --pid $$
Do not confuse a shell's limits with a system-wide setting. They belong to that process and pass down to anything it starts. A service launched by systemd, a container runtime or another supervisor can end up with completely different numbers.
3. Change a disposable process before you change a real one
Changing a live process is a state change, so rehearse it on something that does not matter. Spin up a child that does nothing useful, shrink its file-descriptor limit, check it took, then kill it:
$ sleep 20 &
$ child=$!
$ prlimit --pid "$child" --nofile=128:256
$ prlimit --pid "$child" --noheadings --output RESOURCE,SOFT,HARD --nofile
NOFILE 128 256
$ kill "$child"
$ wait "$child" 2>/dev/null || true
128:256 sets both parts of the range in one go. The process has to be one you own, and the soft value can never sit above the hard one. If prlimit reports permission denied, do not reach straight for sudo: check the PID and ownership first. Shrinking the wrong process's limit is reversible in principle but can still knock a service over in the meantime.
There is nothing to undo here beyond killing the test process, which throws its changed limits away with it. If you did change a real process, restore the pair you recorded beforehand, for example --nofile=OLD_SOFT:OLD_HARD, assuming you wrote it down and still have permission.
4. Learn the four ways to write a limit
prlimit accepts four forms. Pick the one that matches the change you actually want:
| Form | Meaning |
|---|---|
soft:hard | Set both values separately. |
soft: | Set only the soft value, keep the current hard value. |
:hard | Set only the hard value, keep the current soft value. |
value | Set both values to the same number. |
Warning
unlimited or -1 removes the ceiling entirely for a resource. Treat that as a security decision, not a convenience: it can let a process eat far more descriptors, memory, processes or CPU than the host was ever sized for. Check the result straight after making the change.
5. Launch a command already under a limit
The safer pattern in production is to apply the limit at launch rather than bolt it onto something already running. The limit is inherited by the command and everything it spawns:
$ prlimit --cpu=1 /bin/sh -c 'printf "%s\n" child-ok'
child-ok
This sets both the soft and hard CPU-time limits to one second for that shell command. It caps CPU time, not wall-clock time: a program that mostly sleeps can run for ages while barely touching a CPU limit. A command that does exceed its CPU limit gets killed by the kernel, so do not trial this against a production workload without a recovery plan already in mind.
Arguments after the command belong to that command, not to prlimit. Quote paths and arguments as normal, and never build the option string from untrusted input. Here is a harmless file-descriptor check that starts a shell with a lower limit and reads it straight back:
$ prlimit --nofile=128:256 /bin/sh -c \
'prlimit --pid $$ --noheadings --output RESOURCE,SOFT,HARD --nofile'
NOFILE 128 256
When the command exits, its temporary limit disappears with it, which makes command mode good for trialling a worker or a one-off job before you touch a supervisor's configuration at all.
6. Read the common failures correctly
A missing or invalid resource name is a syntax problem, not a permissions one. Compare it against prlimit --help; the installed binary lists names like core, data, fsize, nofile, nproc, stack and as. Do not borrow a similarly-named setting from a different tool.
A limit change can fail for several reasons: the PID has already exited, the process belongs to someone else, the requested hard limit is too high, or the pair breaks the soft-must-not-exceed-hard rule. Re-run the check against the exact PID and capture the exit status:
$ sleep 5 & child=$!
$ kill "$child"
$ wait "$child" 2>/dev/null || true
$ prlimit --pid "$child" --nofile=128:256
$ status=$?
$ printf 'prlimit status: %s\n' "$status"
prlimit: failed to set the NOFILE resource limit: No such process
prlimit status: 1
The exact wording and status can shift with util-linux version and failure type. A non-zero status only tells you the requested change did not land; it is not evidence that some other resource got changed instead. Never treat a failed limit change as a working safety control.
Remember prlimit changes process state, not the service definition. For anything long-running, put the intended limit into the service manager or container config after testing, then restart through the normal change process. Keep the old configuration to hand until the new limit has proved itself under real load.
Done means
- Confirmed the binary and version your shell actually calls.
- Read a process's limits with a chosen output column and understood soft versus hard.
- Changed only a disposable process, or recorded the old values before touching a real one.
- Told apart a per-command limit from a persistent service configuration.
- Verified every change and never reached for
unlimitedwithout a clear reason.