Layer 8Ehrlicher Tech-Support

PostgreSQL: Langer Report bricht nach exakt 30 Sekunden ab

Der Monatsbericht bricht immer zur gleichen Sekunde ab. Kein Absturz, sondern statement_timeout, pro Rolle oder vom Pool gesetzt, nicht in der conf.

Aufwand:
ca. 20 Min.
Voraussetzung:
psql oder ein anderer SQL-Client, Das Recht, SHOW auszuführen, und für dauerhafte Änderungen das Recht für ALTER ROLE oder ALTER DATABASE, Zugriff auf die Konfiguration der Anwendung oder des Verbindungspools, der die Verbindung aufbaut
Gilt für:
PostgreSQL 18 laut Dokumentation unter docs/current (Kapitel 19.11 Client Connection Defaults, 19.1 Setting Parameters), abgerufen am 17.10.2026

Das Symptom

Der Monatsbericht wird aus der Datenbank gezogen, eine Abfrage über mehrere große Tabellen. Sie läuft an, die Last steigt, und nach 30 Sekunden ist Schluss: Die Anwendung meldet einen Fehler mit dem Wortlaut canceling statement due to statement timeout, der Server läuft weiter, nichts ist abgestürzt. Der Versuch von Hand in psql, als Administrator, läuft dagegen zwei Minuten und liefert das Ergebnis.

Die Suche beginnt in postgresql.conf. Dort steht nichts von einem Timeout. Also wird der Server verdächtigt, die Netzverbindung, der Pool, das Betriebssystem. Dabei ist die Zahl das Verräterische: Ein Absturz passiert zu zufälligen Zeiten, ein Timeout immer zur selben Sekunde.

Die „Layer 8“-Wahrheit

Der Server tut, was ihm jemand gesagt hat, nur nicht in der Datei, in der man nachsieht. statement_timeout bricht laut Dokumentation jede Anweisung ab, die länger als die angegebene Zeit braucht, gemessen von der Ankunft des Befehls bis zur Fertigstellung durch den Server. Die Voreinstellung ist null, also aus. Ein Abbruch nach exakt 30 Sekunden ist deshalb kein Serverfehler, sondern ein gesetzter Wert.

Dass er in postgresql.conf nicht steht, hat einen Grund, der in der Dokumentation selbst steht: „Setting statement_timeout in postgresql.conf is not recommended because it would affect all sessions.“ Wer den Rat befolgt hat, hat den Wert pro Rolle oder pro Datenbank gesetzt, oder der Verbindungspool und der Treiber der Anwendung schicken ihn beim Verbindungsaufbau mit. Laut Kapitel Setting Parameters überschreiben Werte aus ALTER ROLE und ALTER DATABASE die Konfigurationsdatei und gelten als Vorgabe für jede neue Sitzung dieser Rolle. Der Administrator in psql hat eine andere Rolle, einen anderen Pool und deshalb einen anderen Wert. Dass sein Versuch durchläuft, beweist nicht, dass die Anwendung spinnt, sondern dass sie anders konfiguriert ist.

Der Wert ist in aller Regel absichtlich da. Für die Rolle einer Webanwendung ist ein kurzer statement_timeout ein Schutz: Eine entgleiste Abfrage blockiert nicht minutenlang eine Verbindung aus dem Pool. Das Problem ist nicht der Timeout, sondern dass der Monatsbericht mit derselben Rolle und denselben Regeln läuft wie ein Klick im Browser. Die Dokumentation legt den Ausweg nahe, ohne ihn zu nennen: Werte pro Rolle. Eine Berichtsrolle mit langem Timeout, eine Anwendungsrolle mit kurzem, und für den Einzelfall SET LOCAL innerhalb der Transaktion, wodurch die Änderung mit dem COMMIT wieder verschwindet.

Zwei Feinheiten verhindern falsche Schlüsse. Erstens zählt der Timeout pro Anweisung: „If multiple SQL statements appear in a single simple-query message, the timeout is applied to each statement separately.“ Ein Skript aus vielen kurzen Anweisungen läuft durch, eine einzelne lange nicht, und vor Version 13 war das laut Dokumentation anders. Zweitens gibt es Nachbarn mit ähnlichem Namen: lock_timeout greift nur beim Warten auf Sperren, transaction_timeout beendet die ganze Sitzung, wenn die Transaktion zu lange dauert. Wer die drei verwechselt, sucht beim falschen Parameter.

Am Ende ist die Zahl 30 die beste Spur, die ein Fehler hinterlassen kann. Sie steht irgendwo, mit Einheit oder als 30000 Millisekunden, und SHOW statement_timeout in der richtigen Sitzung zeigt sie. Danach ist es keine Störung mehr, sondern eine Entscheidung, wer wie lange rechnen darf.

Die echte, verifizierte Lösung

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

  1. 1.

    Den wirksamen Wert in der betroffenen Sitzung lesen

    Entscheidend ist der Wert in der Sitzung, in der der Bericht läuft, nicht der in psql des Administrators. Am besten lässt man die Anwendung selbst SHOW statement_timeout ausführen oder verbindet sich mit derselben Rolle, über denselben Pool. Steht dort 0, kommt der Abbruch nicht von diesem Parameter, und man prüft lock_timeout und transaction_timeout sowie Zeitlimits in Pool, Treiber oder Webserver. Steht dort 30s, ist die Ursache gefunden und nur noch die Herkunft offen.

    SHOW statement_timeout;
    SHOW lock_timeout;
    SHOW transaction_timeout;
    
  2. 2.

    Die Herkunft des Werts finden

    Die Einstellung kann pro Rolle, pro Datenbank, in der Konfigurationsdatei oder durch den Client gesetzt sein. Die Rollen- und Datenbankvorgaben stehen im Katalog pg_db_role_setting; die Abfrage listet alle rollen- und datenbankspezifischen Konfigurationen. Taucht statement_timeout dort nicht auf und steht auch nichts in postgresql.conf, setzt der Client den Wert beim Verbinden, also der Treiber, ein ORM oder ein Pool. Dann liegt die Korrektur in der Anwendungskonfiguration, nicht in der Datenbank.

    SELECT r.rolname, d.datname, s.setconfig
      FROM pg_db_role_setting s
      LEFT JOIN pg_roles r ON r.oid = s.setrole
      LEFT JOIN pg_database d ON d.oid = s.setdatabase;
    
  3. 3.

    Für den einzelnen Bericht den Timeout in der Transaktion anheben

    Wenn der Bericht legitim lange braucht und nur einmal im Monat läuft, reicht eine Ausnahme in der Sitzung. SET LOCAL innerhalb der Transaktion hebt den Wert nur für diese Transaktion an; nach COMMIT gilt wieder die Vorgabe der Rolle. Der Wert darf eine Einheit tragen; ohne Einheit sind laut Dokumentation Millisekunden gemeint, 600 wären also 0,6 Sekunden und nicht zehn Minuten. 0 schaltet den Timeout für diese Transaktion ganz ab, was für Berichte mit unbekannter Laufzeit tragbar ist, solange niemand die Transaktion offen liegen lässt.

    BEGIN;
    SET LOCAL statement_timeout = '10min';
    -- Berichtsabfrage hier
    COMMIT;
    
  4. 4.

    Eine eigene Rolle für Berichte mit eigenem Wert anlegen

    Dauerhaft sauber ist eine getrennte Rolle für Auswertungen. ALTER ROLE setzt den Wert laut Dokumentation als benutzerspezifische Vorgabe, wirksam für neue Sitzungen dieser Rolle. Die Rolle der Webanwendung behält ihren kurzen Timeout, damit eine entgleiste Abfrage dort nicht minutenlang Ressourcen bindet; die Berichtsrolle bekommt einen langen oder gar keinen. Beide Werte sind dann an einer Stelle dokumentiert und im Katalog pg_db_role_setting sichtbar, statt in Treiberoptionen verstreut zu sein.

    ALTER ROLE berichte SET statement_timeout = '30min';
    
  5. 5.

    Den Timeout nicht als Feind behandeln

    Ein statement_timeout von 30 Sekunden für die Rolle einer Webanwendung ist eine gute Einstellung, kein Fehler. Er verhindert, dass eine einzelne schlecht geplante Abfrage die Verbindung des Pools und die Prozessorzeit des Servers für Minuten belegt. Laut Dokumentation wird die abgebrochene Anweisung protokolliert, wenn log_min_error_statement auf ERROR oder niedriger steht; das Log zeigt dann, welche Abfrage zu lange brauchte, und oft fehlt schlicht ein Index. Der Bericht gehört in eine eigene Rolle; die Abfrage, die im Webkontext abbricht, gehört optimiert.

Häufige Fragen (FAQ)

?Was genau tut statement_timeout?

Der Parameter bricht jede Anweisung ab, die länger dauert als angegeben. Die Dokumentation: „Abort any statement that takes more than the specified amount of time.“ Gemessen wird laut Dokumentation von der Ankunft des Befehls am Server bis zu seiner Fertigstellung durch den Server. Ohne Einheit gilt der Wert als Millisekunden, und null, die Voreinstellung, schaltet den Timeout ab. Dass der Bericht nach genau 30 Sekunden abbricht, bedeutet also: Irgendwo ist ein Wert von 30s oder 30000 gesetzt worden, denn ab Werk greift nichts.

?Warum ist in postgresql.conf nichts davon zu finden?

Weil die Dokumentation genau davon abrät. Zu statement_timeout heißt es: „Setting statement_timeout in postgresql.conf is not recommended because it would affect all sessions.“ Üblich ist deshalb das Setzen pro Rolle oder pro Datenbank. Laut Kapitel Setting Parameters erlaubt ALTER ROLE, globale und datenbankweite Einstellungen mit benutzerspezifischen Werten zu überschreiben; die Werte gelten für neu gestartete Sitzungen und bilden die Vorgabe für den Rest der Sitzung. Auch ein Verbindungspool oder der Datenbanktreiber der Anwendung kann den Wert beim Verbindungsaufbau setzen. SHOW zeigt, was in der eigenen Sitzung tatsächlich gilt.

?Kann ich den Timeout für den einen Report aufheben, ohne ihn für alle zu ändern?

Ja, in der Sitzung selbst. Die Dokumentation beschreibt, dass PostgreSQL nach dem Verbinden Befehle bereitstellt, um sitzungslokale Einstellungen zu ändern; SET setzt den Wert für die laufende Sitzung. Mit SET LOCAL gilt die Änderung nur bis zum Ende der aktuellen Transaktion, was für einen einzelnen Bericht innerhalb von BEGIN und COMMIT der sauberere Weg ist. Nach COMMIT gilt wieder der Vorgabewert der Rolle. Für den Berichtsdienst, der immer lange Abfragen stellt, ist eine eigene Rolle mit eigenem Wert die dauerhafte Lösung.

?Gilt der Timeout für die ganze Abfragefolge oder jede Anweisung einzeln?

Jede Anweisung einzeln. Die Dokumentation: „If multiple SQL statements appear in a single simple-query message, the timeout is applied to each statement separately.“ Sie ergänzt in Klammern, dass PostgreSQL-Versionen vor 13 den Timeout üblicherweise auf die ganze Abfragezeichenkette anwandten. Ein Skript aus zehn Anweisungen, die je 20 Sekunden brauchen, läuft also bei 30s Timeout durch, während eine einzelne Anweisung mit 31 Sekunden abbricht. Wer von einer alten Version kommt, erlebt hier eine Verhaltensänderung.

?Wo liegt der Unterschied zu lock_timeout und transaction_timeout?

lock_timeout bricht laut Dokumentation nur Anweisungen ab, die beim Warten auf eine Sperre länger als angegeben hängen; außerhalb des Wartens auf Sperren greift er nicht. Die Dokumentation weist darauf hin, dass es wenig Sinn hat, lock_timeout gleich groß oder größer als statement_timeout zu setzen, weil dann immer zuerst der Anweisungs-Timeout auslöst. transaction_timeout beendet dagegen die ganze Sitzung, wenn eine Transaktion länger als angegeben dauert, und ist er kürzer oder gleich idle_in_transaction_session_timeout oder statement_timeout, wird laut Dokumentation der längere Timeout ignoriert. Alle drei stehen ab Werk auf null.

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.