Understanding Linux Signals - SIGTERM vs SIGKILL
What You'll Learn
- The difference and proper use of
SIGTERM,SIGKILL, andSIGHUP - A grounded answer to "should I just use
kill -9?" - A clear way to diagnose why a process "won't die" or "won't reload its config"
Quick Summary
- Try
kill(=SIGTERM) first to stop the process gracefully - If it doesn't respond, use
kill -KILL(=SIGKILL) to force it - Don't reach for
kill -9reflexively — it's the last resort that skips cleanup
What Is a Signal?
Conclusion: A signal is an asynchronous notification the kernel sends to a process, telling it to terminate, stop, reload, and so on.
A signal is an asynchronous software interrupt sent to a process, usually by the kernel. It carries a short message — "please terminate", "please stop" — encoded as a number, and is one of the lightest forms of inter-process communication (IPC).
Signals arrive through three main paths.
- Keyboard:
Ctrl+C→SIGINT,Ctrl+Z→SIGTSTP kill/pkillcommands: send any signal to any process- Kernel / other processes:
SIGKILLon memory pressure (OOM Killer),SIGSEGVon an invalid memory access
List the available signals with kill -l.
$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM ...
Signal numbers are not all fixed. The low ones — SIGHUP(1), SIGINT(2), SIGKILL(9), SIGTERM(15) — are stable, but others like SIGUSR1 vary by architecture. In scripts, prefer the name (-TERM, -KILL) over the number.
What Is SIGTERM, and Why Is It the Default?
Conclusion: SIGTERM (15) politely asks a process to exit. The process can catch it, clean up (save files, close connections), then quit. It's the default for kill.
SIGTERM (number 15) is the signal kill sends when you don't specify one.
# These two are equivalent $ kill 12345 $ kill -TERM 12345
The key property of SIGTERM is that a process can catch it. Before exiting, the process can perform cleanup:
- Save files being edited
- Close database connections and sockets
- Delete temporary files
- Notify child processes to shut down
This is a graceful shutdown, and it's exactly why systemd sends SIGTERM first when stopping a service.
When stopping data-handling processes (databases, editors, app servers), always try SIGTERM first. Force-killing immediately risks data corruption.
What Is SIGKILL, and How Does It Differ from SIGTERM?
Conclusion: SIGKILL (9) makes the kernel destroy a process instantly. It cannot be caught, ignored, or blocked, and no cleanup runs — a true last resort.
SIGKILL (number 9) is the force kill behind the familiar kill -9. The decisive difference from SIGTERM comes down to one point.
Only SIGKILL and SIGSTOP cannot be caught, ignored, or blocked by a process.
The kernel terminates the process without ever running its handlers, so no cleanup code executes.
That means kill -9 carries side effects:
- Unsaved data is lost
- Open files and sockets are not closed cleanly
- Temporary and lock files are left behind
- Child processes become orphans
The OS reclaims some of this, but application-level consistency is not guaranteed.
| Aspect | SIGTERM (15) | SIGKILL (9) |
|---|---|---|
| Catchable? | Yes | No |
| Cleanup runs? | Yes | No |
| Data saved? | Likely | No |
| When to use | Normal stop | When TERM fails |
Avoid starting with kill -9. "It won't stop, so just use -9" tends to hide the real cause (deadlock, I/O wait) while throwing away data. Stick to the order: SIGTERM first, wait a few seconds, then SIGKILL if needed.
What Is SIGHUP, and Its Use Beyond Termination
Conclusion: SIGHUP (1) originally meant "the terminal hung up," but daemons reuse it by convention as a "reload your config file" trigger.
SIGHUP (number 1, "hang up") was originally sent when the controlling terminal was disconnected. Close a terminal, and processes started there receive SIGHUP and, by default, terminate. The nohup command exists precisely to ignore SIGHUP and keep running.
Separately, many daemons interpret SIGHUP their own way: as a signal to reload the configuration file without restarting.
# Tell nginx to reload its config (without stopping the process) $ kill -HUP $(cat /var/run/nginx.pid)
This "reload" behavior is not part of the signal spec — it's a convention each daemon implements. Behavior varies per program, so always check the official docs for how it handles SIGHUP.
SIGINT, SIGSTOP, and Other Key Signals
Conclusion: The everyday signals are SIGINT (Ctrl+C) and SIGTSTP (Ctrl+Z). SIGSTOP / SIGCONT are uncatchable and pause/resume a process.
Know the signals you'll hit most often in a terminal.
SIGINT(2):Ctrl+C. "Interrupt." Terminates by default but is catchable (this is why many CLIs show a confirmation prompt).SIGTSTP(20):Ctrl+Z. Suspends the foreground job; resume withfg/bg.SIGSTOP(19) /SIGCONT(18): Pause and resume a process. LikeSIGKILL,SIGSTOPis uncatchable.SIGQUIT(3):Ctrl+\. Terminate plus a core dump.
Handling jobs suspended with Ctrl+Z is covered in detail in Job Control Basics.
Sending Signals in Practice: kill / pkill / killall
Conclusion: Use kill for a PID, pkill / killall for a name. To avoid mistakes, confirm the targets with pgrep before sending.
There are three common commands for sending signals.
# Send to a specific PID (the basic form) $ kill -TERM 12345 # Send by process name (partial match) $ pkill -TERM nginx # Send by process name (exact match, killall) $ killall -TERM nginx
pkill / killall send to every matching process. To avoid catching unintended processes, always confirm the targets with pgrep -a <name> first.
$ pgrep -a nginx
To express "TERM first, then KILL" in one line, insert a wait in between.
$ kill -TERM 12345; sleep 5; kill -KILL 12345 2>/dev/null
Summary: Signal Cheat Sheet
Conclusion: SIGTERM for a graceful stop, SIGKILL as the last resort, SIGHUP to reload config. Specify by name, not number, and keep force-kill for last.
| Goal | Signal | Example |
|---|---|---|
| Stop normally | SIGTERM | kill <PID> |
| It just won't stop | SIGKILL | kill -KILL <PID> |
| Reload config | SIGHUP | kill -HUP <PID> |
| Pause / resume | SIGSTOP / SIGCONT | kill -STOP / -CONT |