Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: March 25, 2025
Linux offers a robust mechanism for setting hard and soft limits via the ulimit utility. Since this is the de facto standard for capping system resource usage, it’s also integrated with the systemd initialization system and its units.
In this tutorial, we describe how to set limits in systemd units. First, we map systemd to ulimit settings. Next, we check how to set limits in systemd unit files. Finally, we discuss defaults.
We tested the code in this tutorial on Debian 11 (Bullseye) with GNU Bash 5.1.4. It should work in most POSIX-compliant environments.
To begin with, we can map systemd unit limit properties to their equivalent ulimit commands:
+------------------+-----------+--------------------------+------+
| systemd | ulimit | Description | Used |
+------------------+-----------+--------------------------+------+
| LimitCORE= | ulimit -c | core files size | Yes |
| LimitDATA= | ulimit -d | data segment size | No |
| LimitNICE= | ulimit -e | niceness level | Yes |
| LimitFSIZE= | ulimit -f | file size | No |
| LimitSIGPENDING= | ulimit -i | queued signals | Yes |
| LimitMEMLOCK= | ulimit -l | locked memory size | Yes |
| LimitRSS= | ulimit -m | resident set size | No |
| LimitNOFILE= | ulimit -n | open file descriptors | No |
| LimitMSGQUEUE= | ulimit -q | POSIX message queue size | Yes |
| LimitRTPRIO= | ulimit -r | real-time priority | Yes |
| LimitRTTIME= | ulimit -R | runtime before blocking | Yes |
| LimitSTACK= | ulimit -s | stack size | Yes |
| LimitCPU= | ulimit -t | CPU time | No |
| LimitNPROC= | ulimit -u | available processes | - |
| LimitAS= | ulimit -v | process virtual memory | No |
| LimitLOCKS= | ulimit -x | file lock count | Yes |
+------------------+-----------+--------------------------+------+
Importantly, the default unit of all size limits is bytes, LimitCPU uses seconds, while LimitRTTIME is in microseconds. The rest are unitless numbers and levels.
Of course, we can also append unit specifiers to change the default when assigning:
+----------+-------------------------+--------------+
| Quantity | Designation | Unit |
+----------+-------------------------+--------------+
| Size | K | Kilobytes |
| Size | M | Megabytes |
| Size | G | Gigabytes |
| Size | T | Terabytes |
| Size | P | Petabytes |
| Size | E | Exabytes |
+----------+-------------------------+--------------+
| Time | usec, us, µs | Microseconds |
| Time | msec, ms | Milliseconds |
| Time | seconds, second, sec, s | Seconds |
| Time | minutes, minute, min, m | Minutes |
| Time | hours, hour, hr, h | Hours |
| Time | days, day, d | Days |
| Time | weeks, week, w | Weeks |
| Time | months, month, M | Months |
| Time | years, year, y | Years |
+----------+-------------------------+--------------+
Furthermore, some limits are better avoided or have no effect, so they are marked as No in the Used column. For example, MemoryMax= usually handles memory restrictions better than LimitDATA, LimitNOFILEor LimitAS, while LimitRSS doesn’t work on Linux. A better equivalent of LimitNPROC is TasksMax=.
For example, let’s see a SAMBA service unit file:
$ cat /usr/lib/systemd/system/smbd.service
[Unit]
Description=Samba SMB Daemon
Documentation=man:smbd(8) man:samba(7) man:smb.conf(5)
Wants=network-online.target
After=network.target network-online.target nmbd.service winbind.service
[Service]
Type=notify
PIDFile=/run/samba/smbd.pid
LimitNOFILE=16384
EnvironmentFile=-/etc/default/samba
ExecStartPre=/usr/share/samba/update-apparmor-samba-profile
ExecStart=/usr/sbin/smbd --foreground --no-process-group $SMBDOPTIONS
ExecReload=/bin/kill -HUP $MAINPID
LimitCORE=infinity
[Install]
WantedBy=multi-user.target
Here, we see two limits:
If we simply assign to a specific systemd option as in the smbd.service file, both the hard and soft limits are set:
LimitNOFILE=16384
On the other hand, we can set each separately by separating them with a colon like SOFT:HARD:
LimitNOFILE=8192:16384
Finally, we can remove limits in systemd via infinity in the same way that we can use unlimited with ulimit.
For limits that we don’t set explicitly, systemd-system.conf provides options to set defaults. In fact, the names of the default values in systemd-system.conf are equivalent to the Limit* options but have a Default prefix.
Specifically for systemd user services, Linux also has predefined kernel and per-user values. Of course, user services can’t set limits above those of their environmental context. In other words, a login process may set limits below those of a user service. In that case, the former generally overrides the latter.
So, we can mostly lower limits in user services. While raising them is possible, it requires privileges or special mechanics like encapsulating the actual manager that runs the user service.
In this article, we saw how to set limits within systemd units.
In conclusion, most ulimit flags are available as Limit* options when using systemd unit files, but they should be used with care.