Every process on a Linux system is competing for the same limited CPU time, and the kernel’s scheduler has to decide who goes first. Most of the time you don’t need to think about this — the default scheduling does a perfectly good job. But every so often I need to run something CPU-heavy (a backup, a big compile, a batch data job) without it stealing responsiveness from everything else on the box, and that’s exactly what nice is for. Here’s everything I know about controlling process priority on Linux.
What is the nice Command?
nice launches a new process with a modified scheduling priority — informally called its “niceness.” The name comes from the idea that a process with a higher niceness value is being “nicer” to other processes, voluntarily yielding more CPU time to them. A lower niceness value means the process is less willing to share, and gets scheduled more aggressively.
Niceness values range from -20 (highest priority, least “nice”) to 19 (lowest priority, most “nice”). The default niceness for any newly launched process is 0.
Basic Syntax
nice [OPTION] [COMMAND [ARGUMENT...]]
Run with no arguments, nice just prints the current niceness (usually 0):
nice
Output:
0
Common Parameters
| Option | Description |
|---|---|
-n <adjustment> | Set the niceness adjustment relative to the current value (default adjustment is 10 if -n is omitted but a command is given) |
--adjustment=<n> | Long-form equivalent of -n |
--help | Show usage information |
--version | Show version information |
Practical Examples
Run a command with default niceness increase
nice mycommand
If you run nice with a command but no explicit -n, it applies a default adjustment of +10, making the process notably less CPU-aggressive than a normal process.
Run a command with a specific niceness
nice -n 15 tar -czf backup.tar.gz /data
I use this constantly for backup jobs — compression and archiving are CPU-heavy but not time-critical, so I want them to yield to anything more important running at the same time.
Run a command with maximum niceness (lowest priority)
nice -n 19 ./long-running-batch-job.sh
Attempt to increase priority (requires root)
sudo nice -n -10 ./latency-sensitive-process
Only root (or a user granted the CAP_SYS_NICE capability, or permitted via /etc/security/limits.conf) can set a negative niceness — i.e., raise a process’s priority above the default. Regular users can only make a process nicer (increase its value), never the reverse, which makes sense from a security standpoint: you don’t want any user able to starve other users’ processes of CPU time.
Check the exact confirmed niceness of a process
ps -o pid,ni,cmd -p <pid>
Or from within top, the NI column shows exactly this value for every running process.
Changing the Priority of an Already-Running Process: renice
nice only sets priority at launch time. To change the priority of a process that’s already running, use renice:
renice -n 10 -p 4521
This is a close cousin worth knowing well:
renice [-n] priority [-p pid] [-u user] [-g pgrp]
Example — deprioritize every process owned by a specific user:
sudo renice -n 15 -u backupuser
Understanding Niceness vs. Priority (PR) in top/ps
This distinction confuses people constantly, so let me clarify it directly. In top‘s output:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
- NI is the niceness value you (or the process itself) set — the user-facing “-20 to 19” scale.
- PR is the actual kernel scheduling priority the kernel computes, which for normal processes is
20 + NI. So a niceness of0corresponds to aPRof20; a niceness of-10corresponds toPRof10; a niceness of10corresponds toPRof30. LowerPRnumbers mean higher actual scheduling priority.
Some processes show PR as rt — meaning they’re running under a real-time scheduling policy entirely separate from the standard niceness scale, and niceness doesn’t apply to them at all.
How nice Works Internally
nice is a thin wrapper around the setpriority() system call (or, historically, the older nice() syscall), which adjusts a value the Linux kernel’s Completely Fair Scheduler (CFS) — the default scheduler on modern Linux — uses when calculating how much CPU time each process should receive relative to others.
Internally, CFS doesn’t literally give a process at niceness -20 twenty times more CPU than one at niceness 0; niceness values are converted into scheduling weights, and CFS uses those weights to proportionally divide available CPU time among all runnable processes. A process with a lower niceness gets a larger weight and, correspondingly, a larger share of CPU time whenever there’s contention — but it’s not a hard, absolute priority order like some older scheduling models. If the CPU isn’t contended at all, niceness has essentially no observable effect, since every process gets as much CPU as it needs regardless.
This is an important, often-missed point: nice only matters when there’s CPU contention. On an idle or lightly loaded system, a process at niceness 19 runs exactly as fast as one at niceness -20, because there’s no competition for CPU time to arbitrate.
Real-World Use Cases
Background compression/archival jobs:
nice -n 19 tar -czf /backups/full-backup-$(date +%F).tar.gz /var/www
Compiling large codebases without freezing your desktop:
nice -n 10 make -j$(nproc)
Batch data processing scripts that shouldn’t compete with a live application:
nice -n 15 python3 nightly_report_generator.py
Combining nice with ionice for I/O-heavy background tasks: CPU niceness alone doesn’t help if the real bottleneck is disk I/O. ionice is the analogous tool for I/O scheduling priority:
nice -n 15 ionice -c2 -n7 rsync -av /data /backup/
This tells the process to yield both CPU time and disk I/O bandwidth to everything else on the system — exactly what I want for a background sync job running alongside a production database.
Real-World Shell Scripting Example
#!/bin/bash
# nightly-batch.sh — run heavy batch jobs at low priority during off-hours
LOGFILE="/var/log/nightly-batch.log"
echo "Starting nightly batch at $(date)" >> "$LOGFILE"
nice -n 19 ionice -c2 -n7 /opt/scripts/generate-reports.sh >> "$LOGFILE" 2>&1
nice -n 19 ionice -c2 -n7 /opt/scripts/cleanup-old-logs.sh >> "$LOGFILE" 2>&1
echo "Nightly batch completed at $(date)" >> "$LOGFILE"
Troubleshooting Common Issues
“nice: cannot set niceness: Permission denied” — You’re trying to set a negative value (increase priority) without root privileges. Either run with sudo or accept a positive (lower-priority) value instead.
A niced process still seems to be slowing everything down — Remember that niceness only affects CPU scheduling, not I/O or memory pressure. A memory-heavy process at niceness 19 can still cause swapping and slow down the whole system; that’s a memory problem, not a CPU scheduling problem — nice won’t help. Check ionice for I/O contention instead.
Niced process doesn’t seem to run any slower on an idle system — This is expected behavior, not a bug. Niceness only has a visible effect under CPU contention.
Child processes not inheriting the nice value as expected — Child processes generally do inherit their parent’s niceness by default via fork(), but any wrapper script or process manager that explicitly resets priority (some systemd unit files set an explicit Nice= value, for instance) can override this.
Performance Optimization Best Practices
- Use
nicefor CPU-bound background jobs (compression, batch processing, video encoding) that don’t need to complete quickly and shouldn’t compete with foreground/interactive work. - Pair with
ionicewhenever the job is also I/O-heavy — CPU niceness alone won’t help disk-bound tasks. - On multi-core systems, remember niceness affects how contested CPU cores are shared — a niced process on an otherwise-idle core sees no penalty at all.
- Avoid setting negative niceness casually; boosting a process’s priority can genuinely starve other important system processes if overused.
Security Implications
Since only root (or users with the CAP_SYS_NICE capability) can lower niceness values (raise priority), this is a deliberate safeguard against unprivileged users starving the system by hogging CPU priority. On multi-tenant systems, I always check /etc/security/limits.conf for nice entries to understand exactly what priority range each user or group is permitted, since misconfigured limits can either be overly restrictive (annoying) or overly permissive (a resource-abuse risk).
nice vs. Related Commands
| Command | Difference |
|---|---|
renice | Changes the niceness of an already-running process, rather than at launch time |
ionice | Controls I/O scheduling priority rather than CPU scheduling priority |
chrt | Manages real-time scheduling policies (SCHED_FIFO, SCHED_RR) entirely outside the standard niceness scale |
cpulimit | Caps a process’s CPU usage to an absolute percentage, rather than a relative scheduling weight like nice |
cgroups (via systemd-run --scope or cgcreate) | A more powerful, modern mechanism for limiting CPU, memory, and I/O for a group of processes together, often preferred over nice alone in containerized/production environments |
Compatibility Across Distributions
nice and renice are part of GNU coreutils/util-linux and are present on every mainstream Linux distribution — Debian, Ubuntu, RHEL, CentOS, Fedora, Arch, openSUSE. The niceness scale (-20 to 19) and its interaction with the CFS scheduler are consistent across any modern Linux kernel. On BusyBox-based minimal systems, a simplified nice is typically provided with the core -n functionality intact.
Nice Values and systemd Services
For long-running services rather than one-off commands, setting niceness through a systemd unit file is generally cleaner and more maintainable than wrapping the ExecStart line in nice:
[Service]
ExecStart=/opt/myapp/bin/worker
Nice=10
IOSchedulingClass=best-effort
IOSchedulingPriority=7
This achieves the same CPU deprioritization as nice -n 10, but ties it directly to the service definition, so it persists correctly across restarts and is visible to anyone inspecting the unit file later — much easier to audit than a nice prefix buried inside a wrapper script that someone might eventually “simplify” away by accident.
systemctl show myservice -p Nice
This confirms the effective niceness systemd is applying to a given service, which I check whenever a background service seems to be competing too aggressively with foreground, latency-sensitive workloads on the same host.
The Interaction Between nice and Multi-Core Scheduling
A subtlety that trips people up: niceness affects how CPU time is shared when there’s contention on the same core(s), but on a multi-core system, the kernel’s scheduler is also making load-balancing decisions about which core each process actually runs on. A heavily niced process might still get its own dedicated core if the system has more cores than actively competing processes, in which case it runs at full speed regardless of its niceness value. This is different from cgroup-based CPU quotas, which impose a hard ceiling on CPU consumption regardless of contention — if you need a guaranteed maximum rather than a relative priority, nice alone isn’t the right tool; look at systemd-run --scope -p CPUQuota=20% or direct cgroup manipulation instead.
Practical Comparison: nice vs. cgroup CPU Limits
# nice: relative priority, only matters under contention
nice -n 19 ./batch-job.sh
# cgroup-based hard limit: guaranteed ceiling regardless of contention
systemd-run --scope -p CPUQuota=25% ./batch-job.sh
I reach for plain nice for quick, one-off background tasks where “please yield to everything else” is good enough. I reach for cgroup-based limits when I need a hard, predictable ceiling — for example, capping a noisy background analytics job at exactly 25% of a shared CPU core so it can never accidentally starve a co-located production service, even during a moment when nothing else happens to be running.
Checking Effective Niceness Across a Whole System
When investigating why a server “feels slow” under load, I often want a quick overview of every process’s niceness at once, sorted so the highest-priority (lowest niceness) processes are easy to spot:
ps -eo pid,ni,pri,cmd --sort=ni | head -20
This immediately shows me if something unexpected has been given elevated priority (a negative niceness), which is worth investigating — legitimate high-priority processes are usually well-known system services, and an unfamiliar process running with negative niceness is worth a closer look.
Summary
nice is a small, elegant tool for a problem that comes up constantly in real system administration: how do I run something CPU-intensive without stepping on everything else running at the same time? Understanding that niceness only matters under contention, that it’s a relative weight rather than an absolute guarantee, and that it needs to be paired with ionice for I/O-bound work, is what turns nice from a command you occasionally type into a real tool for managing shared system resources responsibly.
References
- Linux man-pages project,
nice(1): https://man7.org/linux/man-pages/man1/nice.1.html - Linux man-pages project,
renice(1): https://man7.org/linux/man-pages/man1/renice.1.html - Linux man-pages project,
setpriority(2): https://man7.org/linux/man-pages/man2/setpriority.2.html - Linux Kernel CFS Scheduler documentation: https://www.kernel.org/doc/html/latest/scheduler/sched-design-CFS.html
- GNU Coreutils manual: https://www.gnu.org/software/coreutils/manual/html_node/nice-invocation.html