Eine hängende Query, eine vergessene Migration, ein Tool, das die Connection nicht freigibt — manchmal müssen Sessions zwangsweise beendet werden. PostgreSQL bietet dafür zwei Stufen: pg_cancel_backend als „bitte hör auf” und pg_terminate_backend als „du gehst jetzt”. Mit pg_stat_activity siehst du, wer überhaupt verbunden ist.
Wer ist gerade verbunden? — pg_stat_activity
Die zentrale Sicht ist pg_stat_activity. Sie zeigt jeden Backend-Prozess mit User, Datenbank, Client-IP, aktueller Query und State:
SELECT pid, usename, datname, client_addr, state,
state_change, query
FROM pg_stat_activity
WHERE state IS NOT NULL
ORDER BY state_change;Beispiel-Ausgabe:
pid | usename | datname | client_addr | state | state_change | query
-------+----------+---------+--------------+---------------------+-----------------------+-------------------
12345 | app_user | myapp | 10.0.0.5 | active | 2026-05-06 11:32:17+00| SELECT ...
12346 | bob | myapp | 10.0.0.7 | idle in transaction | 2026-05-06 09:15:08+00| BEGIN
12347 | reporting| myapp | 10.0.0.8 | idle | 2026-05-06 11:30:00+00|Die wichtigsten state-Werte:
| State | Bedeutung |
|---|---|
active | Session führt gerade eine Query aus |
idle | Session ist verbunden, aber gerade untätig |
idle in transaction | Session hat eine offene Transaktion und tut nichts — gefährlich! |
idle in transaction (aborted) | Transaktion ist abgebrochen, aber ROLLBACK/COMMIT fehlt |
idle in transaction ist der häufigste Auslöser für „mein VACUUM macht keinen Fortschritt mehr”: eine offene Transaktion verhindert, dass tote Tupel weggeräumt werden.
Lange laufende Queries finden
SELECT pid, usename, datname,
now() - query_start AS duration,
state, query
FROM pg_stat_activity
WHERE state = 'active'
AND now() - query_start > interval '5 minutes'
ORDER BY duration DESC;Praktisch als Live-Dashboard mit \watch 5 in psql:
myapp=# SELECT pid, now()-query_start AS dur, query
FROM pg_stat_activity WHERE state='active';
myapp=# \watch 5Sanftes Abbrechen — pg_cancel_backend
pg_cancel_backend(pid) sendet das Signal „bitte aktuellen Befehl abbrechen”. Die Session selbst bleibt verbunden.
SELECT pg_cancel_backend(12345);Anwendungsfall: eine Reporting-Query läuft seit Stunden und blockiert Ressourcen — du willst sie stoppen, der User kann aber an seiner psql-Session bleiben und eine andere Query absetzen.
Wichtig: pg_cancel_backend wirkt nur auf aktive Queries. Eine idle in transaction-Session ignoriert das Signal — dafür brauchst du pg_terminate_backend.
Endgültiges Beenden — pg_terminate_backend
pg_terminate_backend(pid) zieht der Session den Stecker. Die Connection wird geschlossen, offene Transaktionen werden gerollt, der Backend-Prozess endet.
SELECT pg_terminate_backend(12346);Wer darf das? Default: nur Superuser oder Mitglieder von pg_signal_backend. Eine Rolle kann immer ihre eigenen Sessions beenden — andere Sessions nur mit höherem Privileg.
GRANT pg_signal_backend TO oncall;Alle Sessions eines Users beenden
Praktisch z. B. nach dem Ausscheiden eines Mitarbeiters:
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE usename = 'bob'
AND pid <> pg_backend_pid();pg_backend_pid() schließt die eigene Session aus, sonst würdest du dich selbst beenden.
Datenbank droppen — alle Connections schließen
Wer DROP DATABASE myapp; ausführt, sieht häufig:
ERROR: database "myapp" is being accessed by other users
DETAIL: There are 3 other sessions using the database.Erst alle Connections beenden, dann droppen:
-- Verhindern, dass neue Connections aufgebaut werden:
REVOKE CONNECT ON DATABASE myapp FROM PUBLIC;
-- Bestehende Connections beenden:
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'myapp'
AND pid <> pg_backend_pid();
-- Drop aus einer ANDEREN Datenbank heraus
-- (man kann eine DB nicht droppen, in der man verbunden ist):
\c postgres
DROP DATABASE myapp;Ab PG 13 gibt es eine Abkürzung:
DROP DATABASE myapp WITH (FORCE);FORCE beendet bestehende Connections automatisch und droppt dann. Praktisch, aber sollte nicht reflexartig genutzt werden — Datenverlust durch versehentliches Beenden von Production-Sessions.
Connection-Listen filtern
Häufige Filter:
SELECT pid, usename, datname,
now() - state_change AS idle_for, query
FROM pg_stat_activity
WHERE state = 'idle in transaction'
AND now() - state_change > interval '1 minute';SELECT application_name, count(*) AS connections
FROM pg_stat_activity
WHERE backend_type = 'client backend'
GROUP BY application_name
ORDER BY connections DESC;application_name lässt sich pro Connection vom Client setzen — z. B. in einer Postgres-URL: ?application_name=worker-1. Sehr nützlich, um in pg_stat_activity schnell zu sehen, welcher Service welche Sessions hält.
FAQ
Was ist der Unterschied zwischen pg_cancel und pg_terminate?
pg_cancel_backend bricht die laufende Query ab, lässt die Connection bestehen — der Client kann weitermachen. pg_terminate_backend schließt die Connection komplett — der Client bekommt einen Disconnect und muss sich neu verbinden. Wenn du nicht weißt, was du willst, fang mit pg_cancel an; wenn das nicht hilft, eskaliere auf pg_terminate.
Warum scheitert pg_terminate_backend manchmal mit „permission denied“?
Default ist: nur Superuser darf andere Sessions beenden. Wer ohne Superuser arbeiten will, braucht Mitgliedschaft in pg_signal_backend (Predefined Role). Ausnahme: die eigenen Sessions kannst du immer beenden, unabhängig von Privilegien.
idle in transaction — wie verhindere ich das?
idle_in_transaction_session_timeout setzt eine Obergrenze. Beispiel: ALTER ROLE app_user SET idle_in_transaction_session_timeout = '5min'; — länger offene Transaktionen werden vom Server abgebrochen. Standardmäßig auf 0 (deaktiviert), aber in Produktion meist eine gute Idee.
Kann ich eine bestimmte Query identifizieren, ohne die query-Spalte abzufragen?
pg_stat_activity.query zeigt das aktuell laufende Statement. Wenn du nur die letzte LANGE Query suchst, schau auf query_start — der Zeitpunkt, an dem das aktuelle Statement begonnen hat. state_change ist dagegen der Zeitpunkt, an dem der State zuletzt umgesprungen ist (wichtig bei idle in transaction).
Gibt es ein Web-Tool dafuer?
Ja — pgAdmin und DBeaver zeigen pg_stat_activity mit Buttons zum Cancelling/Terminating. Praktisch, aber für Skripte und Cron-Jobs ist die SQL-Variante zuverlässiger. In Notfall-Situationen lieber die Query auswendig kennen, als sich auf eine GUI zu verlassen, die gerade auch nicht reagiert.
DROP DATABASE … WITH (FORCE) ab PG 13.
Die WITH (FORCE)-Variante beendet alle Connections automatisch. Sehr praktisch in CI/Tests („nach jedem Lauf die Test-DB neu”). In Produktion mit Vorsicht — falls eine echte App-Connection drauf hängt, killt das die App.
Weiterführende Ressourcen
Externe Quellen
- pg_stat_activity – PostgreSQL Documentation
- System Administration Functions – pg_cancel_backend, pg_terminate_backend
- Predefined Roles – pg_signal_backend
- DROP DATABASE … WITH (FORCE)
- idle_in_transaction_session_timeout