Cancel vs Terminate PostgreSQL Backends Explained
Cancel vs Terminate PostgreSQL Backends: What Every DBA Should Know
PostgreSQL gives you two tools for dealing with problem backends: pg_cancel_backend() and pg_terminate_backend(). They sound similar but behave very differently. Using the wrong one can disrupt users unnecessarily, or leave a problematic connection in place when you needed it gone entirely.
This guide explains both functions, when to use each, and how to identify the right PIDs to target.
Sample Code
Cancel a running query (leaves the connection open):
1SELECT pg_cancel_backend(pid);
Terminate a backend entirely (closes the connection):
1SELECT pg_terminate_backend(pid);
Find PIDs to target using pg_stat_activity:
1SELECT
2 pid,
3 usename,
4 application_name,
5 client_addr,
6 state,
7 wait_event_type,
8 wait_event,
9 now() - query_start AS query_duration,
10 left(query, 100) AS query_preview
11FROM
12 pg_stat_activity
13WHERE
14 pid <> pg_backend_pid()
15 AND state <> 'idle'
16ORDER BY
17 query_duration DESC NULLS LAST;
Cancel or terminate multiple sessions at once:
1-- Cancel all queries running longer than 5 minutes
2SELECT pg_cancel_backend(pid)
3FROM pg_stat_activity
4WHERE state = 'active'
5 AND query_duration > interval '5 minutes'
6 AND pid <> pg_backend_pid();
7
8-- Terminate all connections from a specific application
9SELECT pg_terminate_backend(pid)
10FROM pg_stat_activity
11WHERE application_name = 'bad_app'
12 AND pid <> pg_backend_pid();
Notes: Both functions take a process ID (PID) as their argument and return true if the signal was sent successfully, or false if the backend no longer exists. Returns false rather than an error when the PID is gone.
Code Breakdown
pg_cancel_backend(pid)— Sends aSIGINTsignal to the target backend. This cancels the current query but leaves the database connection open. The client receives acancellationerror and can immediately run another query.pg_terminate_backend(pid)— Sends aSIGTERMsignal to the target backend. This terminates the entire connection. The client loses its connection and must reconnect.pg_backend_pid()— Returns the PID of your own session. Thepid <> pg_backend_pid()condition prevents you from accidentally canceling or terminating your own connection.pg_stat_activity— The system view that lists all active backends. Used here to find PIDs worth targeting and to filter by state, duration, user, or application.state <> 'idle'— Focuses on backends that are actually doing something. Idle connections are not running queries, so canceling them has no effect.now() - query_start— Calculates how long the current query has been running. Useful for finding long-running queries.left(query, 100)— Truncates the query text to 100 characters for readable output. Full query text is in thequerycolumn.
Key Points
pg_cancel_backend()is the gentler option. Use it first. If the query is stuck in a wait state (not actively running), it may not respond to a cancel signal.pg_terminate_backend()always works for clearing a connection but forces the client to reconnect. Use it for idle-in-transaction sessions, sessions holding locks, or connections that did not respond to a cancel.- Both functions return
false(not an error) if the PID no longer exists by the time the signal is sent. This is safe — it just means the backend already finished.
Insights and Explanations
When cancel does not work:
pg_cancel_backend() sends a cancel signal, but the backend only checks for it at certain points. If a query is stuck waiting on a lock — shown as state = 'active' with wait_event_type = 'Lock' in pg_stat_activity — the cancel signal will not take effect until the lock is acquired. In that case, you need to resolve the lock conflict or use pg_terminate_backend().
Idle in transaction:
A session in state idle in transaction has started a transaction but is not currently running a query. It may be holding locks that block other sessions. A cancel signal does nothing here because there is no active query to cancel. Use pg_terminate_backend() to clear these sessions:
1SELECT pg_terminate_backend(pid)
2FROM pg_stat_activity
3WHERE state = 'idle in transaction'
4 AND now() - state_change > interval '10 minutes';
The difference in what the client sees:
- After
pg_cancel_backend(): the client getsERROR: canceling statement due to user request. The connection stays alive. - After
pg_terminate_backend(): the client getsFATAL: terminating connection due to administrator command. The connection drops.
Additional Considerations
- Permissions: Superusers can cancel or terminate any backend. Regular users can only cancel or terminate their own backends. To let a non-superuser manage other sessions, grant the
pg_signal_backendrole (PostgreSQL 14+). - Replication connections: Terminating a replication backend will briefly disconnect a standby. It will reconnect automatically, but replication lag may spike.
- Autovacuum workers: You can cancel autovacuum workers with
pg_cancel_backend(). PostgreSQL will restart the autovacuum process. Only do this if the autovacuum is actively blocking other work.
References
Posts in this series
- Identify Blocking PostgreSQL Queries with pg_stat_activity
- PostgreSQL query to find columns containing only NULL values
- Analyze PostgreSQL Cache-Hit Ratio with pg_stat_statements
- How to Monitor Slow Running Queries in PostgreSQL
- Find Idle in Transaction Sessions in PostgreSQL
- Monitor PostgreSQL Index Build Progress with SQL
- Find PostgreSQL Tables That Need VACUUM FREEZE
- Detect PostgreSQL Transaction ID Wraparound Risk
- Cancel vs Terminate PostgreSQL Backends Explained