Skip to content
DevOps AI ToolKit
Newsletter
All prompts
AI for Postgres Difficulty: Advanced ClaudeChatGPTCursor

Postgres Idle-in-Transaction Session Remediation Prompt

Track down long 'idle in transaction' sessions that hold locks and pin the xmin horizon so autovacuum can't reclaim dead tuples, then decide what to terminate, what to fix in the app, and which timeouts to set — before bloat and lock waits cascade into an outage.

Target user
DBAs and SREs debugging lock waits, bloat, and stuck vacuum on production Postgres
Difficulty
Advanced
Tools
Claude, ChatGPT, Cursor

The prompt

You are a senior PostgreSQL DBA. You understand that a session sitting in "idle in
transaction" is not harmless idle time: it still holds any locks it acquired, and its
open snapshot pins the cluster-wide xmin horizon so autovacuum cannot remove dead tuples
newer than that transaction — quietly causing bloat, blocked queries, and in the worst
case wraparound risk. Your job is to identify the offenders, weigh termination against
app-side fixes, and set the timeouts that prevent recurrence.

I will paste:
- pg_stat_activity rows filtered to state = 'idle in transaction' (or
  'idle in transaction (aborted)'), including pid, usename, application_name, state,
  wait_event, xact_start, state_change, backend_xmin, and query: [ACTIVITY]
- Current lock waits: a pg_locks join or the blocked/blocking pids you have: [LOCKS]
- Vacuum / bloat symptoms: pg_stat_user_tables dead tuples or age(datfrozenxid),
  and the oldest backend_xmin you can see: [VACUUM / XMIN]
- Current settings: idle_in_transaction_session_timeout, statement_timeout,
  lock_timeout, and how the app connects (pooler? ORM? long-lived connections?): [SETTINGS / APP]

Work through:

1. **Rank the offenders** — compute how long each idle-in-transaction session has been
   open (now() - xact_start) and how stale its last activity is (now() - state_change).
   Flag the session holding the oldest backend_xmin: that one is pinning the vacuum
   horizon for the whole cluster and is the top priority regardless of the locks it holds.

2. **Map the blast radius** — for each offender, list the locks it holds and which
   sessions are waiting behind it, and note whether its open snapshot is what is blocking
   autovacuum on the bloated tables. Separate "blocking other queries" from "blocking
   cleanup" — both matter, for different reasons.

3. **Decide the action per session** — recommend pg_cancel_backend(pid) to cancel a
   running statement first, and pg_terminate_backend(pid) only to kill a truly stuck idle
   transaction; explain that terminating rolls back its open transaction. Prioritize the
   xmin-pinning session. Call out anything that looks like an app bug (a transaction left
   open across a network round-trip or user think-time).

4. **Prevent recurrence** — propose idle_in_transaction_session_timeout (globally or per
   role for the offending app user), and the app-side fix (don't hold a transaction open
   across external calls; use autocommit or shorter transactions; check pooler settings).
   Give exact SET / ALTER ROLE / ALTER SYSTEM statements.

Output format: (a) offender table [pid | user/app | idle for | oldest xmin? | locks held |
waiters], (b) ordered actions with the exact pg_terminate_backend / pg_cancel_backend calls,
(c) the timeout and app-side prevention settings, (d) a re-check query on pg_stat_activity
and backend_xmin.

Guardrails: pg_terminate_backend rolls back the target's open transaction — confirm you are
killing the right pid and that a rollback is acceptable before running it. Do not set an
aggressive global idle_in_transaction_session_timeout without checking that legitimate
long-running batch jobs won't be killed; scope it per role where possible.

Run this prompt with AI

Test it, get an AI-improved version, or compare models — live in the Prompt Workspace. No copy-paste.

Why this prompt works

“Idle in transaction” is one of the most misread states in Postgres. It looks like a connection doing nothing, but the transaction is still open: it holds every lock it took and, more insidiously, its snapshot pins the cluster’s xmin horizon so autovacuum cannot reclaim any dead tuple newer than that transaction. The result is creeping bloat and blocked queries whose root cause is a session that appears idle. This prompt makes that invisible cost explicit by keying the diagnosis on backend_xmin and xact_start, not just on visible lock waits.

It also separates two failure modes engineers routinely conflate: a session blocking other queries versus a session blocking cleanup. Both come from the same idle transaction, but they demand different reasoning — one shows up as lock waits, the other as vacuum falling behind — so the prompt asks for both and singles out the oldest-xmin session as the top priority even when it holds no contended locks.

By forcing a per-session decision between pg_cancel_backend and pg_terminate_backend, and pairing every kill with a prevention step (idle_in_transaction_session_timeout plus the app-side pattern that left the transaction open), the output becomes a safe runbook rather than a blunt “kill the connections.” The guardrails keep termination deliberate and stop an over-aggressive timeout from taking out legitimate batch jobs.

Related prompts

More Postgres prompts & error guides

Browse every Postgres prompt and troubleshooting guide in one place.

Free download · 368-page PDF

Reading prompts? Get all 500 in one free PDF

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.