Search... ⌘K
Write Log In Sign Up

Join DevSolved

Share war stories & investigate outages.

Sign Up for Free Log In to Account
ESC
CRITICAL Resolved

PostgreSQL Transaction ID Wraparound: The Read-Only Lockdown

Avatar Devsolved Sep 10, 2023 — 16:00 UTC MTTR: 24 hours 1 min read 195000 views
Executive Summary

Our primary Postgres cluster suddenly stopped accepting all write operations and forced itself into read-only mode to prevent catastrophic data corruption due to transaction ID exhaustion.

Database Impact: 4 hours of total write downtime. No users could sign up, purchase, or modify data.

The Symptom

Symptom

Every single `INSERT`, `UPDATE`, or `DELETE` query failed instantly with the error: `ERROR: database is not accepting commands to avoid wraparound data loss in database "production"`.

Root Cause Analysis

Root Cause

PostgreSQL uses a 32-bit integer for Transaction IDs (XIDs), allowing ~2 billion transactions. To reuse IDs safely without older data disappearing (becoming "invisible"), Postgres runs a background process called "autovacuum" to freeze old transaction IDs. A massive, long-running data migration script had been running for 5 days. This long-running transaction blocked autovacuum from freezing any rows. The XID counter eventually hit the 2-billion limit, forcing Postgres into read-only mode to prevent catastrophic data loss.

Resolution

Resolution

We had to SSH into the database instances, forcefully terminate the hanging data migration transaction using `pg_cancel_backend()`, and then run an aggressive manual `VACUUM FREEZE` in single-user mode. This process took 4 hours due to disk I/O constraints.

Preventive Action Items

critical Add Datadog alerts for `xid_age` > 1.5 billion @DBA Team
high Set `idle_in_transaction_session_timeout` to 5 minutes to kill hung scripts automatically @DBA Team
|

Discussions 0

Most recent