Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

Manage processes on Linux

By updated

Improve this page

Five commands are enough to master Linux processes: ps, top, kill, nice and renice. With them, you will identify the process that hogs a CPU, adjust its priority, and stop it cleanly, without ever rebooting the server.

What you will learn

  • List every active process with ps aux and ps -eo
  • Find a PID by name with pgrep and pidof
  • Read the STAT codes (R, S, D, Z, T) and understand what they signal
  • Monitor in real time with top
  • Adjust the priority at launch (nice) and on a running process (renice)
  • Stop cleanly: SIGTERM → wait → SIGKILL sequence
  • Explore /proc/$PID/status and lsof to diagnose

In which context?

You need these commands as soon as a server behaves abnormally, and the symptom tells you which one to reach for first:

  • a process has used 100 % of a CPU for several minutes,
  • a service shows up several times in ps aux (process leak),
  • a job is stuck in state D (I/O wait) and no longer responds,
  • a Z zombie piles up and never goes away,
  • you must stop a service cleanly before maintenance.

List processes with ps

Display every process

ps aux takes a snapshot of every process on the system at a given moment, those of other users included. It is the first move of a diagnosis, before filtering or sorting.

Terminal window
ps aux

Key columns:

ColumnMeaning
USEROwner
PIDUnique identifier
%CPUPercentage of CPU used
%MEMPercentage of memory
STATState (see below)
COMMANDCommand started

Choose the columns with ps -eo

Terminal window
ps -eo pid,ppid,user,ni,stat,comm --sort=-%cpu | head -n 11

--sort=-%cpu sorts by decreasing usage, the minus sign carrying the inversion. head -n 11 keeps the header line plus the first ten processes: with head -n 10 you would only get nine, since the header counts as one line. The percentage shown is an average since the process started (the ps manual calls it a "cputime/realtime" ratio), not an instant measurement. Measured on a process that computed for five seconds then sleeps: ps still shows 55 %, top shows 0.0 %. For the instant value, top remains the right tool.

Read the STAT states

The STAT column is the first to check when a process "does nothing". It combines an uppercase letter giving the kernel state, then optional attribute characters. Two values call for action: D signals an input/output wait that no signal interrupts, and Z a process already finished that its parent has not reaped. The others are normal operation, S being by far the most frequent on an idle server.

CodeMeaning
RRunning
SSleeping (interruptible)
DBlocked on I/O (uninterruptible)
ZZombie (finished, parent has not read the exit code)
TStopped (Ctrl+Z or SIGSTOP)
sSession leader
+Foreground process
lMulti-threaded
<High priority (negative nice value)
NLow priority (positive nice value)

Find a process by name

pgrep looks for a pattern in process names, not an exact name: pgrep lee finds a sleep (measured). Add -x to require the full name, and -a to display the command line. pidof, for its part, expects the exact program name.

Terminal window
# By pattern in the name (-x for the exact name)
pgrep nginx
# Several PIDs (several instances)
pidof bash
# Pattern in ps with a self-excluding filter
ps aux | grep '[n]ginx'

The [n]ginx trick excludes the line of grep itself: the bracketed pattern does match the string nginx, but the command line of grep contains the brackets and therefore does not match its own pattern. Without this precaution, you always see at least one result, even when the service is stopped.

Display the process tree

pstree draws the parent-child hierarchy of processes; the -p option adds the PIDs. It belongs to the psmisc package, present in the measured Debian 13 image but missing from the Ubuntu 24.04 and AlmaLinux 10 images: install this package if the command is missing.

Terminal window
pstree -p

Useful to understand parent-child relationships, identify an orphan process, or see the threads of a service.

Monitor in real time with top

Where ps freezes a snapshot, top refreshes its display every three seconds by default (two frames in 3.2 s, measured on Debian 13). This is the difference that matters for a diagnosis: the %CPU column of top measures the interval elapsed since the previous refresh, so it reflects the current activity and not the lifetime average of the process. Measured with procps-ng 4.0.4, this holds from the first frame: a process asleep after five seconds of computing shows 0.0 % there, where ps keeps 55 %.

Terminal window
top

Useful interactive keys:

KeyAction
PSort by CPU
MSort by memory
kSend a signal to a process
rChange the priority (renice)
qQuit

Execution priority: nice and renice

Each process has a nice value from −20 (high priority) to +19 (low priority). The default is 0. The higher it goes, the less the process is favoured by the scheduler.

Start a process with a reduced priority

nice -n sets the value at launch, before the process takes any CPU:

Terminal window
nice -n 15 tar czf archive.tar.gz /data

Handy for long jobs (backups, compilations) that must not disturb the other services.

Change the priority of a running process

renice acts on a process already running, without restarting it: it is what saves a backup started without nice on a heavy-load day. Its output gives the old and new value (old priority 3, new priority 5), and a refusal shows clearly: renice: failed to set priority for 1234 (process ID): Permission denied, with exit code 1. Still frame the command with two readings of the NI column: they are the proof that the priority changed.

Terminal window
# Check the current value
ps -o pid,ni,comm -p 1234
# Change the priority
renice -n 10 -p 1234
# Check afterwards
ps -o pid,ni,comm -p 1234

Beware of a syntax trap: with the util-linux version shipped by Debian, Ubuntu and RHEL (2.39 to 2.41), -n sets an absolute value. It is not added to the current value: measured, renice -n 5 on a process at 3 gives 5, and renice --relative 2 then moves it to 7. The behaviour also switches to relative when the POSIXLY_CORRECT variable is present in the environment.

Send signals to a process

Common signals

A signal is a notification sent to a process by the kernel. Most can be caught by the program, which then decides what to do with it: this is exactly what lets nginx reload its configuration on SIGHUP without dropping the connections in progress. Two exceptions in the table below, SIGKILL and SIGSTOP, which the kernel applies without giving the program the slightest chance to react. Remember the names rather than the numbers: kill -TERM works everywhere, whereas the numbering varies with the hardware architecture.

NumberNameEffect
1SIGHUPConfiguration reload
2SIGINTKeyboard interrupt (Ctrl+C)
15SIGTERMClean stop request (default)
9SIGKILLImmediate forced stop (cannot be caught)
19SIGSTOPPause (cannot be caught)
18SIGCONTResume after a pause

Ask politely first, check, and only then force: each step gives the process a chance to close its files cleanly.

Terminal window
# 1. Clean stop request
kill -TERM 1234
# 2. Wait a few seconds, then check
sleep 3 && ps -p 1234
# 3. Force only if the process still does not respond
kill -9 1234

Kill by name with pkill and killall

Working by name avoids the round trip through pgrep to get a PID, but the trade-off is real: the command hits every process that matches, those of other users included. Get into the habit of running pgrep -a <name> first to see the exact list of targets before sending anything. Without privileges, each process out of your reach produces pkill: killing pid … failed: Operation not permitted. Measured: the exit code stays 0 when at least one process received the signal, it moves to 1 when all were refused.

Terminal window
# First see what will be hit, with the full command line
pgrep -a nginx
# Send SIGTERM to every process named "nginx"
pkill -TERM nginx
# Restrict to your own processes
pkill -u "$USER" -TERM nginx
# Ask nginx to reread its configuration (PID of the master process)
kill -HUP "$(cat /run/nginx.pid)"
# Kill every process with a given name (killall)
killall -SIGTERM firefox

pkill looks for a pattern in the name, killall requires the full command name by default. Practical consequence: pkill ngin reaches nginx, killall ngin finds nothing. Both belong to different packages, procps for pkill and psmisc for killall, and killall is not always installed: measured, it is missing from the Ubuntu 24.04 and AlmaLinux 10 images. For a service managed by systemd, prefer systemctl reload to a kill -HUP: systemd knows which process to target.

Explore /proc to diagnose

Linux exposes the information of each process in /proc/<PID>/, a virtual directory the kernel fills on the fly: it is the source that ps and top read themselves.

Terminal window
# Card of the current process
cat /proc/$$/status
# Extract the useful fields
grep -E "^(Name|Pid|PPid|State|VmRSS)" /proc/1234/status

Sample output:

Name: nginx
State: S (sleeping)
Pid: 1234
PPid: 1
VmRSS: 8560 kB

List the files opened by a process

lsof (list open files) lists the files, sockets and libraries a process keeps open. It was installed in none of the three measured images: the package is called lsof everywhere. Without it, ls -l /proc/1234/fd already gives the list of open descriptors.

Terminal window
lsof -p 1234

Or to find which process uses a port, with ss as an alternative (iproute2 package, installed on any server):

Terminal window
lsof -i :80
sudo ss -tlnp 'sport = :80'

Troubleshooting

The six situations below cover almost every call received on this topic. Read them in the symptom then cause direction before applying the solution: the first two lines look alike on screen but have nothing in common. A process that kill -9 does not reach is a hardware or network mount problem, not a signal problem; resending the signal will change nothing.

SymptomLikely causeSolution
kill -9 1234 does not kill the processState D (I/O blocked, uninterruptible)Diagnose the I/O subsystem (disk, NFS)
pkill nginx finds nothingCommand name differs from the binaryUse pgrep to confirm the exact name
renice refused with Permission deniedNon-root user lowering the nice value, even from 10 to 5Use sudo renice
pstree or killall not foundpsmisc package missingInstall psmisc
Z zombie that never goes awayThe parent process has not called wait()Find the parent with ps -o ppid -p $ZOMBIE, kill the parent if possible
top no longer refreshesFrozen terminalq or Ctrl+C, then start again

Key points

  • ps aux lists every process; ps -eo chooses the columns.
  • pgrep <pattern> (or pgrep -x <name> for the exact name) and ps aux | grep '[n]ame' find a PID by name.
  • The STAT codes (R, S, D, Z, T) give the state, D and Z deserve attention.
  • nice -n N command (priority at launch); renice -n N -p PID (after start, absolute value).
  • Always SIGTERM first, wait, then SIGKILL only if needed.
  • /proc/$PID/status diagnoses without any tool to install; lsof -p $PID completes it once the lsof package is installed.

Knowledge check

Check that the essentials of this guide stuck. The questions cover only what has just been explained here.

Knowledge check

Check what you have learned with this interactive quiz

6 questions
6 min
70% to pass

How it works

  • The timer starts when you click Start
  • Multiple choice, true/false and short answer questions
  • You can move between questions
  • Detailed results are shown at the end

Starts the quiz and the timer

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn