sudo iotop -o shows you, in real time, which process is doing disk I/O right now and how much. It is top for the disk: a live table sorted by I/O rate, with a per-process read column and a write column. The -o flag is the one you actually want, because it hides every thread that is not currently doing any I/O, so the screen shows only the culprits instead of a wall of idle kernel threads.
The thing to know up front: iotop needs root. It reads per-task I/O accounting out of the kernel's taskstats interface over a netlink socket, and that data is privileged, so a plain iotop as a normal user fails with a permission error. Run it with sudo. Everything else on this page is filtering and formatting: collapsing threads into processes, logging to a file instead of a live screen, and showing accumulated totals instead of an instantaneous rate.
The one-liner
sudo iotop -oThat opens the interactive view and lists only processes with active disk I/O, refreshing once a second. The columns that matter are DISK READ and DISK WRITE (the current per-process rate, displayed as B/s, K/s, or M/s) and IO> (the percentage of time the process spent waiting on I/O). The two summary lines at the top show Total DISK READ / Total DISK WRITE (actual disk traffic) and Actual DISK READ / Actual DISK WRITE. Those two pairs differ because of the page cache and writeback: a process can "write" into cache faster than the kernel flushes it to the platter, so the totals and the actuals rarely line up exactly.
Inside the live view, press o to toggle the --only filter, r to reverse the sort, a to switch to accumulated mode, and q to quit. left/right arrows move the sort column.
Why -o is the flag you reach for first
Without -o, iotop lists every thread on the system, including the dozens of idle kernel worker threads. On a busy box that is several screens of noise with the one process you care about buried in it.
sudo iotop -o -P-P (--processes) collapses threads into their parent process, so you see one row per process instead of one row per thread. Combined with -o, that is the view I keep open when something is thrashing the disk: only active processes, one line each, sorted by I/O. If you need the thread-level breakdown (say, one thread of a multithreaded daemon is the problem), drop -P and iotop goes back to per-thread rows.
Logging I/O instead of watching it: batch mode
The interactive view is fine when you are at the keyboard. When you want to capture I/O over time, for a slow nightly job or an intermittent spike, use batch mode and redirect to a file.
sudo iotop -boP -d 5 -n 12 > /tmp/io.logThat reads as: -b batch (non-interactive, plain text, no curses), -o only active, -P per-process, -d 5 a five-second delay between samples, -n 12 stop after 12 samples. Twelve samples at five seconds each is one minute of logging, then iotop exits on its own. Add -t to prefix every line with a timestamp, which you want in any log you are going to read later:
sudo iotop -btoP -d 5 -n 12 > /tmp/io.logBatch mode is also how you feed iotop output into anything else: grep for a process name, awk the write column, or pipe it into a quick chart. The curses view cannot do any of that. For recurring capture, drop a bounded batch run into cron (a short -n run appended to a dated log) rather than leaving an interactive session open.
Accumulated totals vs the instantaneous rate
By default each refresh shows the rate over the last interval. Sometimes you do not care about the rate, you care about who has written the most in total since iotop started. That is -a (--accumulated):
sudo iotop -aoPNow the DISK READ and DISK WRITE columns count total bytes since iotop launched, not a per-second rate. This is the mode for catching a process that writes in short bursts: a per-second rate flickers and is easy to miss, but the accumulated total just keeps climbing for the offender and stays flat for everything else. Press a in the interactive view to toggle it live.
A worked example: tracking down a runaway writer
Suppose iostat or a monitoring alert says the disk is pinned at 100% utilization but you do not know which process is responsible. Open the live view:
sudo iotop -oPTotal DISK READ: 0.00 B/s | Total DISK WRITE: 118.42 M/s
Actual DISK READ: 0.00 B/s | Actual DISK WRITE: 121.06 M/s
PID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
31847 be/4 postgres 0.00 B/s 117.30 M/s 0.00 % 92.14 % postgres: autovacuum worker
2210 be/4 root 0.00 B/s 1.12 M/s 0.00 % 3.01 % rsyslogd
The autovacuum worker is doing 117 MB/s of writes and spending 92% of its time blocked on I/O. That is the answer. The IO> column is the tell: a high percentage there means the process is genuinely I/O-bound, not just incidentally touching the disk. To confirm it is sustained and not a one-second blip, switch to accumulated mode (a) and watch the write total for that PID climb.
iotop vs pidstat vs iostat
These three tools overlap but answer different questions. Pick by what you actually need to know.
| Tool | Granularity | Answers | Needs root |
|---|---|---|---|
iotop | per process / per thread | "Which process is doing the I/O right now?" | Yes |
pidstat -d | per process | "Which process, sampled over time, scriptable?" | No (own processes); yes for all |
iostat -x | per device | "Which disk is busy, and how saturated?" | No |
Reach for iotop when you want a live, sorted, interactive view and you are sitting at the terminal. Reach for pidstat -d when you want the same per-process I/O numbers in a clean, columnar, easily-parsed form for a script or a log, or when you do not have root, since pidstat reports your own processes without it. See the pidstat command guide for the per-process CPU, memory, and I/O breakdown. Reach for iostat -x when the question is about the device, not the process: queue depth, await time, and utilization per disk.
Caveats and distro differences
It is not installed by default. iotop ships in a package you usually have to add: apt install iotop on Debian and Ubuntu, dnf install iotop on Fedora and RHEL-family systems. Some recent distributions ship iotop-c (a C rewrite of the original Python tool) under the same iotop command name; the common flags shown here behave the same.
It needs a kernel built with task I/O accounting. iotop relies on CONFIG_TASK_DELAY_ACCT, CONFIG_TASKSTATS, and CONFIG_TASK_IO_ACCOUNTING being enabled in the kernel. Every mainstream desktop and server distro enables these, but a stripped-down or embedded kernel might not, in which case iotop starts and shows zeroes for everything. On some kernels delay accounting is off until you enable it with sysctl kernel.task_delayacct=1.
Containers and VMs see only their own view. Inside an unprivileged container iotop may fail on the netlink socket entirely, or only report processes in its own namespace. If you need the host's full I/O picture, run iotop on the host, not inside the container.
The page cache hides the truth, briefly. The gap between Total DISK WRITE and Actual DISK WRITE is the writeback delay. A process can appear to write huge amounts that have not hit the disk yet, or appear idle while the kernel flushes its earlier writes. For the real device-level number, cross-check with iostat -x.
See also
- pidstat: per-process CPU, memory, and I/O: the scriptable, no-root-needed way to get the same per-process I/O numbers iotop shows, sampled over an interval
- Find the largest files on a disk: once iotop tells you a process is filling the disk, this is how you find the files it left behind
- nvtop: the same idea for GPUs (NVIDIA, AMD, Intel).
FAQ
Sources
Authoritative references this article was fact-checked against.





