You start a backup. Server crawls. Your monitoring dashboard turns red. Everyone’s cursing your name in Slack.
Sounds familiar? The problem isn’t that backups can’t run—it’s that they’re running at the same priority as everything else. You need to tell Linux: “Hey, this backup is important, but not more important than serving requests.”
That’s what nice and ionice do. They’re your priority knobs.
Nice: CPU Priority
nice ranges from -20 (highest priority) to 19 (lowest priority). Default is 0.
Think of it like airline boarding. -20 is first class. 19 is standby.
$ nice -n 10 backup.shThis runs backup.sh at nice level 10—lower priority than normal. If the CPU is busy, other tasks get more cycles.
$ nice -n -5 critical-job.shThis runs at -5 (higher priority). It’ll preempt lower-priority work.
Only root can go negative. Non-root users can only increase their own niceness (move toward 19).
Renice a Running Process
Started a job at priority 0 but realize it’s killing production? Adjust it on the fly:
$ pgrep -f backup.sh12345
$ renice -n 10 -p 1234512345 (process ID) old priority 0, new priority 10Check it:
$ ps aux | grep backup.shuser 12345 0.0 15.2 ... 10 ? Sl 12:34 5:20 backup.sh ^ that's the NI columnIonice: I/O Priority
CPU nice affects scheduling. But here’s the kicker: I/O is separate. A process can be low CPU priority and still hammer your disk, blocking everyone.
That’s where ionice comes in. It sets I/O scheduling class:
$ ionice -c idle -p 12345Classes are:
- realtime (0) — I/O operations go before everything else. Use almost never.
- best-effort (1) — Default. Priority depends on nice level.
- idle (3) — I/O only happens when nothing else needs the disk. Perfect for backups.
# Run an rsync backup at idle I/O priority$ ionice -c idle rsync -av /home /backup/
# Combine nice + ionice: low CPU, idle I/O$ nice -n 15 ionice -c idle backup.shFor best-effort, you can specify a priority (0-7):
$ ionice -c best-effort -n 5 my-processReal-World Example
Your nightly database dump is tanking the web server. Fix it:
#!/bin/bash# Start at low priorityexec nice -n 10 ionice -c idle mysqldump --single-transaction --all-databases | gzip > /backup/db-$(date +%s).sql.gzOr apply it to an already-running process:
$ pgrep mysqldump5678
$ renice -n 15 -p 5678$ ionice -c idle -p 5678
# Verify$ ps aux | grep mysqldump | grep -v grep$ ionice -p 5678idleWatch It In Action
Before priority tuning:
$ iostat -x 1...util: 95% ← disk is saturatedAfter:
# Terminal 1: Run heavy I/O at idle priority$ ionice -c idle dd if=/dev/zero of=/tmp/test.bin bs=1M count=1000
# Terminal 2: Check I/O still responsive$ time find / -type f > /dev/nullreal 0m2.341s ← still fast!Without ionice, that find would crawl.
Caveats
ionice needs CFQ scheduler. Modern kernels use mq-deadline or bfq. Check:
$ cat /sys/block/sda/queue/scheduler[mq-deadline] kyber bfq noneIf you don’t see cfq, ionice still works but behaves differently. BFQ respects nice more consistently.
Real-world: System load matters. If the server is idle, nice/ionice do nothing. A backup at priority 19 will still zip through if there’s no contention.
Docker/cgroups override this. Containers have their own resource limits. Nice is per-process; cgroups are per-container.
Systemd and Priority
If you’re running a service through systemd, set nice and I/O priority in the unit file instead of a shell wrapper:
[Service]Nice=10IOSchedulingClass=idleExecStart=/usr/local/bin/backup.shReload and restart:
sudo systemctl daemon-reloadsudo systemctl restart backupThis is cleaner than wrapping commands in nice ... ionice ... in a shell script, and it applies every time the service starts — even after reboots.
Verify What’s Actually Set
Check the current nice/ionice of any running process:
# Nice value (NI column)ps -o pid,ni,comm -p $(pgrep backup.sh)
# ionice classionice -p $(pgrep backup.sh)A nice value of 10 means you set it correctly. A class of idle means your I/O prioritization is active. If you see the default (0 and none), your changes didn’t take effect.
When to Use Them
- Backups, log rotation, cleanup:
nice -n 10 ionice -c idle - Monitoring scrapes during peak traffic:
nice -n 5 - Critical services:
nice -n -5(if you control them) - Long-running analysis:
batch+ionice -c idle
Your 2 AM self—the one paged because backups hammered the DB—will be grateful you did this.