Layer 8Ehrlicher Tech-Support

PostgreSQL nimmt keine Befehle mehr an: Wraparound

Die Datenbank verweigert jede schreibende Transaktion. Nicht die Platte ist voll, sondern die Transaktionsnummern gehen aus — Autovacuum kam nicht durch.

Aufwand:
ca. 45 Min.
Voraussetzung:
Datenbankzugang mit Superuser-Rechten, psql
Gilt für:
PostgreSQL 18

Das Symptom

Die Anwendung kann nichts mehr schreiben. Jeder Schreibversuch endet mit einem Fehler, wonach die Datenbank keine Befehle mehr annimmt, die neue Transaktionsnummern vergeben — um Datenverlust durch Wraparound zu vermeiden. Als Hinweis steht dabei, in dieser Datenbank ein datenbankweites VACUUM auszuführen.

Lesen geht meist noch. Die Platte ist nicht voll, der Arbeitsspeicher reicht, die Verbindungen stehen. Im Serverprotokoll finden sich rückblickend Wochen alte Warnungen, dass die Datenbank innerhalb einer bestimmten Anzahl von Transaktionen aufgeräumt werden müsse. Gelesen hat sie niemand.

Die „Layer 8“-Wahrheit

PostgreSQL nummeriert Transaktionen, und dieser Zähler ist endlich. Damit er umlaufen kann, ohne dass alte Daten plötzlich in der Zukunft zu liegen scheinen, müssen alte Zeilenversionen rechtzeitig eingefroren werden. Genau dafür gibt es Autovacuum. Es läuft von allein, es läuft ständig, und es meldet sich, wenn es nicht hinterherkommt. Der Fehler ist also nicht, dass die Datenbank stehen bleibt — der Fehler ist, dass sie es angekündigt hat und niemand hingesehen hat.

Warum Autovacuum nicht durchkommt, ist fast immer dieselbe kurze Liste. Eine Sitzung, die vor drei Wochen ein BEGIN abgesetzt und nie beendet hat. Ein Replikations-Slot für einen Standby-Server, den es seit dem letzten Umbau nicht mehr gibt. Beide tun dasselbe: Sie beanspruchen eine alte Sicht auf die Daten, und solange die besteht, darf Vacuum die betreffenden Zeilen nicht einfrieren. Der Zähler läuft trotzdem weiter.

Der zweite verbreitete Fehler ist die Reparaturanleitung. Ein großer Teil der Ratschläge im Netz schickt einen in den Einzelbenutzermodus, weil das vor vielen Jahren tatsächlich nötig war. Das Handbuch widerspricht heute ausdrücklich: In typischen Fällen ist das nicht mehr erforderlich und sollte vermieden werden, weil es das System außer Betrieb nimmt. Wer also im Ernstfall zuerst den Server herunterfährt, verlängert den Ausfall aus Traditionsgründen.

Die echte, verifizierte Lösung

1000 % faktenbasiert. Jeder Befehl ist real, jeder Pfad existiert. Schritt für Schritt:

  1. 1.

    Feststellen, wie knapp es wirklich ist

    Zuerst den Abstand jeder Datenbank zur ältesten eingefrorenen Transaktionsnummer messen. Das Handbuch nennt genau diese Abfrage als bequemen Weg, die Information einzusehen. Der zurückgegebene Wert ist ein Alter in Transaktionen — je größer, desto dringender. Er gehört in die Überwachung, nicht in eine einmalige Notfallsitzung.

    SELECT datname, age(datfrozenxid) FROM pg_database;
    
  2. 2.

    Die Bremsklötze finden und lösen

    Ein Vacuum, das nicht einfrieren darf, läuft ins Leere. Das Handbuch nennt zwei Hauptverdächtige. Erstens lang laufende offene Transaktionen: in pg_stat_activity nach Zeilen mit großem age(backend_xid) oder age(backend_xmin) suchen und diese Sitzungen beenden. Zweitens alte Replikations-Slots: in pg_replication_slots nach Slots mit großem age(xmin) oder age(catalog_xmin) suchen und nicht mehr benötigte entfernen. Erst danach lohnt das Aufräumen.

    SELECT pid, age(backend_xid), age(backend_xmin), state, query
      FROM pg_stat_activity
     ORDER BY age(backend_xmin) DESC NULLS LAST;
    
    SELECT slot_name, active, age(xmin), age(catalog_xmin)
      FROM pg_replication_slots;
    
  3. 3.

    Datenbankweit aufräumen

    Der im Fehlerhinweis geforderte Schritt: ein datenbankweites VACUUM in der betroffenen Datenbank. Das dauert bei großen Beständen lange und darf nicht abgebrochen werden, weil sonst wieder von vorn begonnen wird. FREEZE erzwingt dabei ein aggressives Einfrieren, statt nur die ohnehin fälligen Bereiche anzufassen.

    vacuumdb --all --freeze --verbose
    
  4. 4.

    Nicht mehr benötigte Tabellen loswerden statt aufräumen

    Wenn große Tabellen ohnehin Müll enthalten, ist es schneller, sie zu entfernen, als sie einzufrieren. Genau das nennt das Handbuch als einzigen verbliebenen Grund, überhaupt in den Einzelbenutzermodus zu gehen: um nicht benötigte Tabellen mit TRUNCATE oder DROP zu beseitigen, damit man sie gar nicht erst aufräumen muss. Im Normalbetrieb geht das genauso — nur mit weniger Drama.

    TRUNCATE TABLE protokoll_alt;
    DROP TABLE import_zwischenstand;
    
  5. 5.

    Dafür sorgen, dass es nicht wieder passiert

    Der Grenzwert, ab dem Autovacuum ein Einfrieren erzwingt, ist autovacuum_freeze_max_age. Das Handbuch beziffert die Vorgabe auf 200 Millionen Transaktionen und rechnet vor, dass das etwa 50 MB Speicher für pg_xact und etwa 2 GB für pg_commit_ts bedeutet. Wer diesen Wert hochsetzt, um Ruhe zu haben, verschiebt nur den Termin der nächsten Notbremse. Sinnvoller ist es, das Alter zu überwachen und Autovacuum nicht auszubremsen — also weder ausschalten noch mit Dauertransaktionen und vergessenen Slots blockieren.

    SHOW autovacuum_freeze_max_age;
    

Häufige Fragen (FAQ)

?Was bedeutet die Meldung, dass die Datenbank keine Befehle mehr annimmt, die neue Transaktionsnummern vergeben?

Sie bedeutet, dass PostgreSQL sich selbst angehalten hat, um Datenverlust zu vermeiden. Das Handbuch nennt genau diesen Fehlertext und gibt als Hinweis dazu, in der betroffenen Datenbank ein datenbankweites VACUUM auszuführen. Vorher wurde bereits gewarnt: Die Datenbank müsse innerhalb einer bestimmten Anzahl von Transaktionen aufgeräumt werden. Es handelt sich also nicht um einen Absturz und nicht um eine defekte Platte, sondern um eine Notbremse, die nach einer langen Reihe ignorierter Warnungen greift.

?Muss ich den Server dafür in den Einzelbenutzermodus herunterfahren?

In aller Regel nein — auch wenn genau das in vielen älteren Anleitungen steht. Das Handbuch sagt heute ausdrücklich, dass es in früheren Versionen manchmal nötig war, den Postmaster anzuhalten und die Datenbank im Einzelbenutzermodus aufzuräumen, dass dies in typischen Fällen aber nicht mehr erforderlich ist und vermieden werden sollte, weil es das System außer Betrieb nimmt. Der einzige genannte Grund für den Einzelbenutzermodus ist, nicht mehr benötigte Tabellen mit TRUNCATE oder DROP loszuwerden, damit man sie gar nicht erst aufräumen muss.

?Warum ist Autovacuum nicht von selbst durchgekommen?

Weil etwas alte Zeilenversionen festhält. Das Handbuch nennt als Prüfschritte, lang laufende offene Transaktionen zu beenden — auffindbar in pg_stat_activity über Zeilen mit großem age(backend_xid) oder age(backend_xmin) — und alte Replikations-Slots zu entfernen, auffindbar in pg_replication_slots über Slots mit großem age(xmin) oder age(catalog_xmin). Solange irgendjemand oder irgendetwas eine alte Sicht auf die Daten beansprucht, darf Vacuum die betreffenden Zeilen nicht einfrieren, und der Abstand wächst weiter.

Belege

Diese Seite ist gegen die folgenden Primärquellen geprüft – Hersteller, Standard oder Gesetzestext. Wer es nicht glaubt, muss es nicht: Da steht, wo es nachzulesen ist.

Zuletzt geprüft am . Dokumentation altert – ein Datum daneben ist der einzige ehrliche Umgang damit.

Auch zu finden unter

Verwandte Fehler

SWLästigconnection refused

PostgreSQL: Connection refused auf Port 5432

Die App erreicht die Datenbank nicht — Connection refused? Meist lauscht PostgreSQL nur auf localhost oder die Client-Freigabe in pg_hba.conf fehlt.

SWLästigpassword authentication failed for user

PostgreSQL: password authentication failed for user

PostgreSQL meldet „password authentication failed“? Falsches Passwort, falscher Nutzer oder pg_hba.conf erlaubt die Methode nicht. So kommst du rein.

SWLästigsorry, too many clients already

PostgreSQL: too many clients already

Die Datenbank weist neue Verbindungen ab? Das Verbindungslimit ist erreicht — meist, weil eine App Verbindungen nicht schließt oder ein Pool fehlt.