Register your handler with signal.signal like this:

#!/usr/bin/env python
import signal
import sys

def signal_handler(sig, frame):
    print('You pressed Ctrl+C!')
    sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)
print('Press Ctrl+C')
signal.pause()

Code adapted from here.

More documentation on signal can be found here.  

Answer from Matt J on Stack Overflow
🌐
Python
docs.python.org β€Ί 3 β€Ί library β€Ί signal.html
signal β€” Set handlers for asynchronous events
A small number of default handlers ... reported as ordinary Python exceptions) and SIGINT is translated into a KeyboardInterrupt exception if the parent process has not changed it....
🌐
Medium
pavolkutaj.medium.com β€Ί explaining-signal-module-in-python-854734318aea
Explaining Signal Module in Python | by Pavol Z. Kutaj | Medium
September 21, 2022 - signal.SIGINT Interrupt from keyboard (CTRL + C). Default action is to raise KeyboardInterrupt.
🌐
Instructables
instructables.com β€Ί circuits β€Ί raspberry pi
Learn How to Capture and Handle OS Signals Like SIGINT (CTRL-C) in Python for Beginners : 6 Steps - Instructables
November 24, 2022 - Learn How to Capture and Handle OS Signals Like SIGINT (CTRL-C) in Python for Beginners: Here we will learn how to capture and handle operating system signals like SIGINT and SIGBREAK on Linux and Windows OS's to control the flow of your python script during execution.
🌐
GeeksforGeeks
geeksforgeeks.org β€Ί python β€Ί how-to-capture-sigint-in-python
How to capture SIGINT in Python? - GeeksforGeeks
July 23, 2025 - ... Step 3: In this step, we define ... function. Also, we define signal.SIGINT, which will perform interruption through the keyboard either by pressing Ctrl+ C or Ctrl+F2....
🌐
Xanthium
xanthium.in β€Ί operating-system-signal-handling-in-python3
Capturing and Handling OS signals like SIGINT (CTRL-C) in Python | xanthium enterprises
October 18, 2023 - A SIGINT signal is generated by the OS (Windows/Linux) and send to the executing script. The Python script then transfer the control to def SignalHandler_SIGINT(SignalNumber,Frame): and then executes the print statement under it "SignalHandler of signal.SIGINT"
🌐
Tutorialspoint
tutorialspoint.com β€Ί python β€Ί python_signal_handling.htm
Python - Signal Handling
Signals can't be used for inter-thread communication. Following are the list of some common signals and their default actions βˆ’ Β· SIGINT βˆ’ Interrupt from keyboard (Ctrl+C), which raises a KeyboardInterrupt.
Find elsewhere
🌐
Python
docs.python.domainunion.de β€Ί 3 β€Ί library β€Ί signal.html
signal β€” Set handlers for asynchronous events β€” Python 3.14.3 documentation
A small number of default handlers ... reported as ordinary Python exceptions) and SIGINT is translated into a KeyboardInterrupt exception if the parent process has not changed it....
🌐
TutorialsPoint
tutorialspoint.com β€Ί how-to-capture-sigint-in-python
How to capture SIGINT in Python?
January 24, 2023 - In this article, we will learn how to capture SIGINT in Python and what has to be done after capturing it. SIGINT is a signal sent when the user presses Ctrl+C (or Ctrl+F2 on Windows) to interrupt a running program.
🌐
Python Module of the Week
pymotw.com β€Ί 2 β€Ί signal
signal – Receive notification of asynchronous system events - Python Module of the Week
$ python signal_getsignal.py SIGHUP ( 1): SIG_DFL SIGINT ( 2): <built-in function default_int_handler> SIGQUIT ( 3): SIG_DFL SIGILL ( 4): SIG_DFL SIGTRAP ( 5): SIG_DFL SIGIOT ( 6): SIG_DFL SIGEMT ( 7): SIG_DFL SIGFPE ( 8): SIG_DFL SIGKILL ( 9): None SIGBUS (10): SIG_DFL SIGSEGV (11): SIG_DFL SIGSYS (12): SIG_DFL SIGPIPE (13): SIG_IGN SIGALRM (14): <function alarm_received at 0x7c3f0> SIGTERM (15): SIG_DFL SIGURG (16): SIG_DFL SIGSTOP (17): None SIGTSTP (18): SIG_DFL SIGCONT (19): SIG_DFL SIGCHLD (20): SIG_DFL SIGTTIN (21): SIG_DFL SIGTTOU (22): SIG_DFL SIGIO (23): SIG_DFL SIGXCPU (24): SIG_DFL SIGXFSZ (25): SIG_IGN SIGVTALRM (26): SIG_DFL SIGPROF (27): SIG_DFL SIGWINCH (28): SIG_DFL SIGINFO (29): SIG_DFL SIGUSR1 (30): SIG_DFL SIGUSR2 (31): SIG_DFL
🌐
W3Schools
w3schools.com β€Ί python β€Ί ref_module_signal.asp
Python signal Module
Python Examples Python Compiler Python Exercises Python Quiz Python Challenges Python Practice Problems Python Server Python Syllabus Python Study Plan Python Interview Q&A Python Bootcamp Python Certificate Python Training ... import signal import sys def handler(signum, frame): print('Signal received, exiting gracefully...') sys.exit(0) signal.signal(signal.SIGINT, handler) print('Press Ctrl+C to trigger signal') Try it Yourself Β»
🌐
AskPython
askpython.com β€Ί home β€Ί python signal module – what are signals and how to create them?
Python Signal Module - What are Signals and How to Create Them? - AskPython
August 6, 2022 - Here, after we run our program, when we press Ctrl + C, the program will go to the signal_handler() function, since we have registered the handler with SIGINT (Ctrl + C). We also have another handler exit_handler() which exits the program if ...
🌐
Readthedocs
cement.readthedocs.io β€Ί en β€Ί 2.10 β€Ί dev β€Ί signal_handling
Signal Handling β€” Cement 2.10.12 documentation
import signal from cement.core.foundation import CementApp from cement.core.exc import CaughtSignal with CementApp('myapp') as app: try: app.run() except CaughtSignal as e: # do something with e.signum or e.frame (passed from signal) if e.signum == signal.SIGTERM: print("Caught SIGTERM...") elif e.signum == signal.SIGINT: print("Caught SIGINT...")
🌐
Marco
blog.marco.ninja β€Ί notes β€Ί technology β€Ί python β€Ί python-handling-signals
Handling signals with Python | marco.ninja
October 25, 2025 - Handling them is possible with Pythons signals library: import signals class SignalHandler: stop = False def __init__(self): # Ctrl+C signal.signal(signal.SIGINT, self.exit_gracefully) # Supervisor/process manager signals signal.signal(signal.SIGTERM, self.exit_gracefully) signal.signal(signal.SIGQUIT, self.exit_gracefully) def exit_gracefully(self, *args): self.stop = True
Top answer
1 of 12
539

A class based clean to use solution:

import signal
import time

class GracefulKiller:
  kill_now = False
  def __init__(self):
    signal.signal(signal.SIGINT, self.exit_gracefully)
    signal.signal(signal.SIGTERM, self.exit_gracefully)

  def exit_gracefully(self, signum, frame):
    self.kill_now = True

if __name__ == '__main__':
  killer = GracefulKiller()
  while not killer.kill_now:
    time.sleep(1)
    print("doing something in a loop ...")
   
  print("End of the program. I was killed gracefully :)")
2 of 12
96

First, I'm not certain that you need a second thread to set the shutdown_flag.
Why not set it directly in the SIGTERM handler?

An alternative is to raise an exception from the SIGTERM handler, which will be propagated up the stack. Assuming you've got proper exception handling (e.g. with with/contextmanager and try: ... finally: blocks) this should be a fairly graceful shutdown, similar to if you were to Ctrl+C your program.

Example program signals-test.py:

#!/usr/bin/python

from time import sleep
import signal
import sys


def sigterm_handler(_signo, _stack_frame):
    # Raises SystemExit(0):
    sys.exit(0)

if sys.argv[1] == "handle_signal":
    signal.signal(signal.SIGTERM, sigterm_handler)

try:
    print "Hello"
    i = 0
    while True:
        i += 1
        print "Iteration #%i" % i
        sleep(1)
finally:
    print "Goodbye"

Now see the Ctrl+C behaviour:

$ ./signals-test.py default
Hello
Iteration #1
Iteration #2
Iteration #3
Iteration #4
^CGoodbye
Traceback (most recent call last):
  File "./signals-test.py", line 21, in <module>
    sleep(1)
KeyboardInterrupt
$ echo $?
1

This time I send it SIGTERM after 4 iterations with kill $(ps aux | grep signals-test | awk '/python/ {print $2}'):

$ ./signals-test.py default
Hello
Iteration #1
Iteration #2
Iteration #3
Iteration #4
Terminated
$ echo $?
143

This time I enable my custom SIGTERM handler and send it SIGTERM:

$ ./signals-test.py handle_signal
Hello
Iteration #1
Iteration #2
Iteration #3
Iteration #4
Goodbye
$ echo $?
0
🌐
GitHub
github.com β€Ί xanthium-enterprises β€Ί OS-Signal-Handling-in-Python
GitHub - xanthium-enterprises/OS-Signal-Handling-in-Python: Basic Signal Handling in Python
How to use and customize operating system signals like SIGINT and SIGBREAK to control the flow of your python script during execution.
Starred by 6 users
Forked by 3 users
Languages Β  Python 99.6% | Batchfile 0.4% | Python 99.6% | Batchfile 0.4%
🌐
DevDungeon
devdungeon.com β€Ί content β€Ί python-catch-sigint-ctrl-c
Python Catch SIGINT (CTRL-C) | DevDungeon
May 26, 2019 - from signal import signal, SIGINT from sys import exit def handler(signal_received, frame): # Handle any cleanup here print('SIGINT or CTRL-C detected. Exiting gracefully') exit(0) if __name__ == '__main__': # Tell Python to run the handler() function when SIGINT is recieved signal(SIGINT, handler) print('Running.