When a Unix Process Is Sluggish Despite Free CPU: Diagnosing and Fixing Nice Values
A process with free CPU available but no progress often has a wrong nice value. Here's how to check the NI column, trace where the priority came from, and fix it with renice, nice, or systemd.
17 Jan 2026, 03:55 UTC

The recognizable condition
A process is running, consuming CPU, and not blocked on I/O — yet it makes progress far slower than expected, or an interactive tool feels laggy while a batch job hogs the machine. top shows plenty of idle CPU overall, but the scheduler keeps favoring other work. This is the classic signature of a priority problem: the process's nice value is working against it.
The nice value is a per-process hint to the kernel's CPU scheduler. On Linux it ranges from -20 (highest priority, most CPU time) to 19 (lowest priority, yields to almost everything). The default is 0. A process niced to 19 will only get CPU when nothing more important wants it — which is exactly right for a background backup, and exactly wrong for your database.
The useful takeaway: before blaming hardware or the application, spend thirty seconds checking the NI column. A wrong nice value is a one-command fix.
Symptom-to-cause table
| What you observe | Likely cause | First check |
|---|---|---|
| Process slow, system otherwise idle | Nice value set high (e.g., 19) by a wrapper script or service unit | ps -o pid,comm,ni -p <PID> |
| Everything lags when one job runs | Batch job running at nice 0 competing with interactive work | Compare NI of the batch job vs. the lagging process |
| Process starts slow every boot | Priority inherited from parent or set in init/systemd config | Check parent's nice value and the unit file |
renice fails with "permission denied" | Non-root user trying to lower the nice value (raise priority) | Run id; only root can set negative nice values |
Ordered checks
Run these as the process owner or root. None of them change state.
- Read the current nice value. Run
ps -o pid,comm,ni -p <PID>(replace<PID>with the process ID). TheNIcolumn shows the value. Anything above 0 means the process is deliberately deprioritized. - Check inheritance. Children inherit their parent's nice value. Find the parent with
ps -o ppid= -p <PID>, then inspect that PID the same way. If a cron job or launcher script runs everything at nice 10, every child starts at 10. - Check how the process is started. On systemd systems, look for a
Nice=directive:systemctl cat <service>. For cron, inspect the crontab for anicewrapper. For manual starts, check shell aliases or wrapper scripts. - Confirm it's actually a scheduling problem. Run
topand watch the process's CPU percentage while the system is busy. If it gets starved only when other load appears, priority is the issue. If it's slow even on an empty machine, the bottleneck is elsewhere (I/O, locks, the application itself) and renicing won't help.
Fixes tied to findings
Fix 1: Reprioritize a running process
Use renice. Note the semantics trap: renice takes an absolute value, not an increment.
# Run as root or the process owner
renice -n 5 -p <PID>
This sets the nice value to 5 (slightly deprioritized). To give a process more CPU, you need root:
sudo renice -n -5 -p <PID>
Permission rules: any user can raise the nice value of their own processes (make them nicer, lower priority). Only root can lower it (raise priority). A non-root user who raises a value generally cannot lower it back — so test with moderate values first.
Fix 2: Start a new process at the right priority
# Start a batch job deprioritized so it won't disturb interactive work
nice -n 15 ./long-report.sh
Here -n 15 is an increment added to the current value (usually 0, so the result is 15).
Fix 3: Make it persistent
renice does not survive a restart. For systemd services, add a directive to the unit (or a drop-in via sudo systemctl edit <service>):
[Service]
Nice=10
Then run sudo systemctl daemon-reload and restart the service. For cron jobs, prefix the command with nice -n 10 in the crontab.
Verify the change
After any adjustment, confirm two things:
- The value stuck:
ps -o pid,comm,ni -p <PID>should show the newNI. - The behavior changed: watch the process's CPU share in
topunder load. A deprioritized batch job should now yield; a boosted process should get a larger share when contention exists. On an idle machine you will see no difference — nice values only matter when processes compete for CPU.
Cautions and escalation
Keep adjustments moderate (±5 to ±10). Setting a critical process to -20 can starve system daemons; setting everything to 19 makes the machine feel dead. Nice values also do nothing for I/O-bound workloads — a process waiting on disk won't speed up no matter its priority (for that, look at ionice, a separate mechanism).
Escalate when: renicing produces no measurable change under load (the bottleneck is elsewhere); you need sustained negative nice values on a shared system (coordinate with the system administrator, since this affects all users); or load spikes are system-wide rather than one misbehaving job — that's a capacity or cgroup/CPU-quota problem, not a nice-value problem.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.