Wissen · Transaktionslog

SQL Server Transaktionslog voll: Fehler 9002 verstehen und beheben

Meist ist das Log nicht zu klein. Etwas hält es fest. Fehler 9002 heißt: SQL Server darf den Platz im Transaktionslog nicht wiederverwenden, und die Datei kann nicht weiter wachsen. Was das Log festhält, steht in der Fehlermeldung selbst. Wer diesen Grund liest, bevor er handelt, schreibt am schnellsten wieder.

Stand 07.11.2026 · ca. 19 Minuten

Lab SQL Server 2017–2025SQL-Abfragen 2Thema LOG_BACKUP · offene Transaktion · CDC

Kurz gesagt

  1. Den Grund lesen. Er steht in der Meldung (full due to 'LOG_BACKUP') und für alle Datenbanken in Abfrage 1, Spalte wartegrund.
  2. Nach dem Grund handeln. Bei LOG_BACKUP eine Logsicherung, bei ACTIVE_TRANSACTION die offene Transaktion finden (Abfrage 2), bei REPLICATION den Leser des Logs wieder in Gang bringen, also Replikation oder Change Data Capture.
  3. Wenn sofort Platz nötig ist: die Logdatei mit SIZE vergrößern oder vorübergehend eine zweite Logdatei anlegen. Nur MAXSIZE anzuheben, reichte im Lab bei erreichter Höchstgröße meist nicht.
  4. Nicht als Erstes: verkleinern, auf SIMPLE umstellen oder gar die Logdatei löschen. Das löst den Grund nicht und kann die Wiederherstellbarkeit kosten.
  5. Danach: die Ursache abstellen und der Logdatei einmal eine passende Größe geben.

Wir haben die häufigsten Fälle auf SQL Server 2017 bis 2025 nachgestellt. Drei Ergebnisse haben uns selbst überrascht:

  • Eine Vollsicherung hilft nicht. Sie gibt das Log nie frei und brach bei vollem Log in 6 von 24 Versuchen sogar ab. Die Logsicherung gelang immer. Mehr dazu
  • Nur die Höchstgröße anzuheben, scheiterte meist selbst an 9002. Die Datei mit SIZE zu vergrößern oder eine zweite Logdatei anzulegen, gelang immer. Mehr dazu
  • Auch in SIMPLE kann das Log volllaufen, etwa durch eine offene Transaktion oder durch Change Data Capture. Mehr dazu

Was Fehler 9002 sagt

Die Anwendung erhält diese Meldung, im Original:

Beispielausgabe
Msg 9002, Level 17, State 2, Line 1
The transaction log for database 'LogFull' is full due to 'LOG_BACKUP' and the holdup lsn is (95:1920:1).

Der Teil in Anführungszeichen ist der Grund. Er entspricht der Spalte log_reuse_wait_desc in sys.databases: der Grund, warum SQL Server den Platz im Log gerade nicht wiederverwenden kann. Ab SQL Server 2022 nennt die Meldung zusätzlich die holdup lsn, also die Stelle im Log, ab der nichts freigegeben werden kann. SQL Server 2017 und 2019 enden nach dem Grund. Bei den drei nachgestellten Gründen unterschied sich der State: 2 bei LOG_BACKUP, 4 bei ACTIVE_TRANSACTION, 6 bei REPLICATION.

Die Datenbank bleibt dabei online. Lesen funktioniert, jede Änderung scheitert, bis wieder Platz da ist. Läuft das Log dagegen während der Wiederherstellung beim Start voll, setzt SQL Server die Datenbank laut Microsoft auf RESOURCE_PENDING; Abfrage 1 zeigt nur Datenbanken, die online sind. Im Lab scheiterten nicht nur die Einfügungen der Anwendung, sondern auch ein CHECKPOINT (Meldung 5901), manche Vollsicherungen und sogar ALTER DATABASE, wenn es nur die Höchstgröße anheben sollte. Mehr dazu unten.

Warum das Log festsitzen kann: SQL Server schreibt jede Änderung zuerst ins Log und verwendet einen Abschnitt erst wieder, wenn nichts mehr ihn braucht. Im Wiederherstellungsmodell FULL braucht ihn die nächste Logsicherung, eine offene Transaktion braucht ihn für ein mögliches Rollback, Replikation oder Change Data Capture brauchen ihn, bis sie ihn gelesen haben. Solange einer davon wartet, wächst die Datei. Kann sie nicht mehr wachsen, kommt 9002.

Den Grund lesen

Abfrage 1 zeigt für alle Datenbanken der Instanz, warum das Log festsitzt, wie voll es ist, wann die letzte Logsicherung lief und ob die Datei noch wachsen kann. Sie liest nur und lässt sich auch dann ausführen, wenn eine Datenbank schon voll ist.

Abfrage 1: Was hält das Log fest? · nur lesend · geprüft auf SQL Server 2017–2025
/* PSG · Transaktionslog · Abfrage 1: Was hält das Log fest? Alle Datenbanken der Instanz   Zeigt je Datenbank Modell, Wartegrund, Größe, Belegung, letzte Logsicherung und ob das Log noch wachsen kann   (über alle Logdateien). Liest nur Systemsichten. Ändert nichts. Ab SQL Server 2017 (sys.dm_db_log_stats).   Auf dem Primary ausführen; auf einem Secondary liefert sys.dm_db_log_stats nur einen Teil der Werte.   Rechte: VIEW SERVER STATE (ab SQL Server 2022 genügt VIEW SERVER PERFORMANCE STATE); für die Spalten zu den   Logdateien zusätzlich VIEW ANY DEFINITION, sonst bleiben sie leer. Letzte Logsicherung aus msdb (nur lokale Historie).   OPTION (MAXDOP 1): Die Diagnose soll keine parallelen Worker belegen, gerade wenn der Server ohnehin unter Druck steht. */SELECT    d.name                                                          AS datenbank,    d.recovery_model_desc                                           AS modell,    d.log_reuse_wait_desc                                           AS wartegrund,    CAST(ls.total_log_size_mb AS decimal(12, 1))                    AS log_mb,    CAST(ls.active_log_size_mb AS decimal(12, 1))                   AS belegt_mb,    CAST(100.0 * ls.active_log_size_mb / NULLIF(ls.total_log_size_mb, 0) AS decimal(5, 1)) AS belegt_prozent,    lb.letzte                                                       AS letzte_logsicherung,    CAST(ls.log_since_last_log_backup_mb AS decimal(12, 1))         AS seit_logsicherung_mb,    ls.total_vlf_count                                              AS vlf,    f.dateien                                                       AS logdateien,    CASE WHEN f.dateien > 1 THEN N'mehrere Dateien' ELSE f.wachstum END AS wachstum,    CASE WHEN f.dateien = 1 THEN f.max_mb END                       AS max_mb,    f.frei_mb                                                       AS frei_laufwerk_mb,    CASE        WHEN ISNULL(f.dateien, 0) = 0 THEN N'unbekannt (Recht fehlt)'        WHEN f.eine_kann = 1 THEN N'ja'        WHEN f.unbekannt = 1 THEN N'unbekannt (Laufwerk nicht lesbar)'        ELSE f.grund    END                                                             AS kann_wachsen,    CASE        WHEN d.log_reuse_wait_desc IN (N'NOTHING', N'CHECKPOINT') AND d.recovery_model_desc <> N'SIMPLE'             AND drs.last_log_backup_lsn IS NULL            THEN N'Noch keine Vollsicherung: Log verhält sich wie SIMPLE, keine Logkette.'        WHEN d.log_reuse_wait_desc = N'LOG_BACKUP' THEN N'Logsicherung fehlt oder läuft zu selten.'        WHEN d.log_reuse_wait_desc = N'ACTIVE_TRANSACTION' THEN N'Offene Transaktion hält das Log: Abfrage 2.'        WHEN d.log_reuse_wait_desc = N'REPLICATION' THEN N'Replikation oder CDC liest das Log nicht ab.'        WHEN d.log_reuse_wait_desc = N'AVAILABILITY_REPLICA' THEN N'Ein Replikat holt nicht auf.'        WHEN d.log_reuse_wait_desc = N'ACTIVE_BACKUP_OR_RESTORE' THEN N'Laufende Sicherung oder Wiederherstellung.'        WHEN d.log_reuse_wait_desc = N'OLDEST_PAGE' THEN N'Meist kurz: Checkpoint hat die älteste Seite noch nicht erreicht.'        WHEN d.log_reuse_wait_desc IN (N'NOTHING', N'CHECKPOINT')             AND ls.active_log_size_mb > 0.8 * ls.total_log_size_mb THEN N'Kein Rückstau, aber voll: Log zu klein für die Last?'        WHEN d.log_reuse_wait_desc IN (N'NOTHING', N'CHECKPOINT') THEN N'Kein Rückstau.'        ELSE N'Wartegrund in der Microsoft-Dokumentation nachschlagen.'    END                                                             AS befundFROM sys.databases AS dJOIN sys.database_recovery_status AS drs ON drs.database_id = d.database_idCROSS APPLY sys.dm_db_log_stats(d.database_id) AS lsOUTER APPLY (    SELECT COUNT(*)                                    AS dateien,           MAX(CASE WHEN x.kann = 1 THEN 1 ELSE 0 END) AS eine_kann,           MAX(CASE WHEN x.kann IS NULL THEN 1 ELSE 0 END) AS unbekannt,           MIN(x.grund)                                AS grund,           MIN(x.wachstum)                             AS wachstum,           MIN(x.max_mb)                               AS max_mb,           MIN(x.frei_mb)                              AS frei_mb    FROM (SELECT              CASE WHEN mf.growth = 0 THEN 0                   WHEN mf.max_size NOT IN (-1, 268435456) AND mf.size >= mf.max_size THEN 0                   WHEN v.available_bytes IS NULL THEN NULL                   WHEN v.available_bytes < CASE WHEN mf.is_percent_growth = 1 THEN mf.size * 8192.0 * mf.growth / 100                                                 ELSE mf.growth * 8192.0 END THEN 0                   ELSE 1 END                                                      AS kann,              CASE WHEN mf.growth = 0 THEN N'nein, Wachstum aus'                   WHEN mf.max_size NOT IN (-1, 268435456) AND mf.size >= mf.max_size THEN N'nein, MAXSIZE erreicht'                   ELSE N'nein, Laufwerk zu voll' END                              AS grund,              CASE WHEN mf.growth = 0 THEN N'kein Wachstum'                   WHEN mf.is_percent_growth = 1 THEN CAST(mf.growth AS nvarchar(10)) + N' %'                   ELSE CAST(mf.growth / 128 AS nvarchar(10)) + N' MB' END          AS wachstum,              CASE WHEN mf.max_size IN (-1, 268435456) THEN NULL ELSE mf.max_size / 128 END AS max_mb,              CAST(v.available_bytes / 1048576.0 AS decimal(14, 0))                AS frei_mb          FROM sys.master_files AS mf          OUTER APPLY sys.dm_os_volume_stats(mf.database_id, mf.file_id) AS v          WHERE mf.database_id = d.database_id AND mf.type = 1) AS x    HAVING COUNT(*) > 0) AS fOUTER APPLY (SELECT MAX(b.backup_finish_date) AS letzte FROM msdb.dbo.backupset AS b             WHERE b.database_name = d.name AND b.type = 'L' AND b.is_copy_only = 0) AS lbWHERE d.state = 0                                                   -- nur ONLINEORDER BY belegt_prozent DESCOPTION (MAXDOP 1);

Auf SQL Server 2022 zeigte Abfrage 1 für die Datenbank aus dem ersten Fall diese Zeile, hier untereinander dargestellt:

Beispielausgabe
datenbank             LogFull
modell                FULL
wartegrund            LOG_BACKUP
log_mb                64.0
belegt_mb             62.6
belegt_prozent        97.8
letzte_logsicherung   NULL
seit_logsicherung_mb  62.6
vlf                   32
logdateien            1
wachstum              8 MB
max_mb                64
kann_wachsen          nein, MAXSIZE erreicht
befund                Logsicherung fehlt oder läuft zu selten.

Abfrage 1 lief auf SQL Server 2017, 2019, 2022 und 2025 ohne Fehler, auch während Datenbanken voll waren. Die Laborgrenze von 64 MB sorgt dafür, dass der Fall in Sekunden eintritt.

So lesen Sie die wichtigsten Spalten:

  • wartegrund ist der Grund aus der Fehlermeldung. NOTHING heißt, nichts hält das Log fest.
  • belegt_prozent zeigt, wie voll das Log gerade ist. Ein großes Log mit kleiner Belegung ist kein Problem, ein kleines Log mit 95 % schon.
  • letzte_logsicherung stammt aus der Sicherungshistorie in msdb, ohne Sicherungen mit COPY_ONLY, denn die geben das Log nicht frei. Das ist die Historie dieser Instanz: Sichern Sie in einer Availability Group auf einem Secondary, steht die Logsicherung dort. Wir lesen sie bewusst nicht aus sys.dm_db_log_stats: Deren Spalte log_backup_time zeigte im Lab nach einer Vollsicherung deren Zeitpunkt, obwohl noch nie eine Logsicherung gelaufen war.
  • kann_wachsen sagt über alle Logdateien der Datenbank, ob noch eine Luft hat: Wachstum ausgeschaltet, MAXSIZE erreicht oder das Laufwerk zu voll für den nächsten Schritt.
  • befund fasst zusammen, was zuerst zu tun ist. Eine Datenbank in FULL ohne erste Vollsicherung wird eigens erkannt (siehe unten).

Die häufigen Gründe und was jeweils hilft

LOG_BACKUP: Die Logsicherung fehlt

Im Wiederherstellungsmodell FULL oder BULK_LOGGED gibt SQL Server einen Abschnitt des Logs erst frei, wenn eine Logsicherung ihn gesichert hat. Läuft keine Logsicherung, wächst das Log, bis es nicht mehr kann. Das ist der häufigste Fall. Im Lab haben wir ihn Schritt für Schritt nachgestellt, Log anfangs 8 MB, Wachstum 8 MB, höchstens 64 MB:

SchrittErgebnis auf SQL Server 2017 bis 2025
90 Einfügungen in FULL, noch ohne Vollsicherungkein Fehler, das Log wuchs von 8 auf 40 MB und wurde wiederverwendet
Vollsicherung, danach weiter einfügennach 52 Einfügungen Fehler 9002 mit LOG_BACKUP, Log 64 MB, davon rund 62 MB belegt
erneute Vollsicherung bei vollem LogWartegrund bleibt LOG_BACKUP; in 6 von 24 Versuchen brach sie zusätzlich mit 9002 ab
Logsicherung bei vollem Loggelang in allen 24 Versuchen, belegt danach 0,1 bis 0,3 MB
Datei nach der Logsicherungweiterhin 64 MB

Drei Dinge daraus sind für den Ernstfall wichtig:

  • Vor der ersten Vollsicherung sitzt das Log nicht fest. Eine frisch angelegte oder auf FULL umgestellte Datenbank ohne Vollsicherung hat noch keine Logkette. Ihr Log wird wiederverwendet wie in SIMPLE. Erst mit der ersten Vollsicherung beginnt die Pflicht zur Logsicherung, nach einem Wechsel von SIMPLE auf FULL auch mit einer Differenzsicherung. Wer FULL einstellt und die Logsicherung vergisst, bemerkt das deshalb oft erst Tage später. Abfrage 1 meldet diesen Zustand als „Noch keine Vollsicherung“.
  • Eine Vollsicherung hilft nicht. Sie gibt das Log nicht frei, und bei vollem Log brach sie in sechs von 24 Versuchen sogar mit 9002 ab (Meldung 3013, BACKUP DATABASE is terminating abnormally.). Einen belegbaren Versionsunterschied sahen wir dabei nicht, bei sechs Versuchen je Version, und der freie Rest im Log war jedes Mal ähnlich, 116 bis 136 KB. Warum sie mal durchläuft und mal nicht, ist offen.
  • Die Logsicherung gelingt auch bei vollem Log. Sie braucht selbst kaum Platz im Log und gibt ihn danach frei. Eine einzige genügte im Lab, obwohl das Log vorher nie gesichert worden war. Microsofts Seite zu 9002 empfiehlt für diesen Fall zwei Logsicherungen; schadet nicht, war hier aber nicht nötig. Die Datei bleibt dabei so groß, wie sie ist. Freier Platz im Log ist das Ziel, nicht eine kleinere Datei.

24 Versuche bei vollem Log

Vollsicherung18 von 24gelungen, keine gibt das Log frei

Logsicherung24 von 24gelungen, Log danach frei

Vollsicherung gelungen, Log bleibt vollabgebrochen mit 9002 und 3013Logsicherung gelungen, Log danach frei

Kein belegbarer Versionsunterschied bei sechs Versuchen je Version (Hauptlauf und fünf Wiederholungen). Freier Rest im Log vor jedem Versuch: 116–136 KB.

Vollsicherung gegen Logsicherung bei vollem Log: je Version sechs Versuche, gemessen im PSG-Lab auf SQL Server 2017 bis 2025.
-- Gibt Platz im Log frei, wenn der Wartegrund LOG_BACKUP ist. Pfad und Name anpassen.BACKUP LOG [IhreDatenbank] TO DISK = N'X:\Backup\IhreDatenbank_log.trn' WITH CHECKSUM;

Schreiben Sie die Sicherung auf ein Ziel mit Platz, nicht auf das Laufwerk, auf dem das Log gerade vollläuft. Und nie nach NUL: BACKUP LOG … TO DISK = 'NUL' gibt das Log zwar frei, wirft die Sicherung aber weg und unterbricht die Logkette.

Danach ist die eigentliche Arbeit die Ursache: Warum lief keine Logsicherung? Ein fehlender Job, ein gescheiterter Job, ein vollgelaufenes Sicherungsziel oder eine Datenbank, die auf FULL steht, ohne dass jemand die Logsicherung eingerichtet hat. Wie Logsicherungen in eine Sicherungsstrategie passen, beschreibt der Beitrag SQL Server Backup und Restore: die Grundlagen.

ACTIVE_TRANSACTION: Eine Transaktion ist noch offen

Solange eine Transaktion offen ist, darf SQL Server den Teil des Logs ab ihrem ersten Eintrag nicht freigeben, denn er braucht ihn für ein mögliches Rollback. Das gilt in jedem Wiederherstellungsmodell, auch in SIMPLE. Im Lab hat eine Sitzung eine Transaktion begonnen, eine Zeile geändert und dann nichts mehr getan, wie eine Anwendung, die das COMMIT vergisst. Eine zweite Sitzung schrieb weiter.

Nach 53 Einfügungen kam 9002 mit ACTIVE_TRANSACTION, auf allen vier Versionen. Ein CHECKPOINT half nicht, er scheiterte selbst mit 9002 und Meldung 5901 (One or more recovery units belonging to database 'HoldTx' failed to generate a checkpoint.).

Die Transaktion selbst hatte kaum Log belegt. Sie hielt aber den Anfang fest, und alles danach musste bleiben. Eine einzelne vergessene Transaktion reicht, um ein Log jeder Größe zu füllen, es dauert nur länger. Mit Accelerated Database Recovery, ab SQL Server 2019 je Datenbank einschaltbar, hält eine lange Transaktion das Log laut Microsoft nicht mehr auf diese Weise fest; im Lab war es ausgeschaltet.

Abfrage 2 zeigt, welche Sitzung es ist:

Abfrage 2: Wer hält das Log fest? · nur lesend · geprüft auf SQL Server 2017–2025
/* PSG · Transaktionslog · Abfrage 2: Wer hält das Log fest? Älteste offene Transaktionen   Zeigt die ältesten Transaktionen, die bereits ins Log geschrieben haben, mit Sitzung, Programm, Dauer und letztem Befehl.   Liest nur Systemsichten. Ändert nichts und beendet keine Sitzung. Ab SQL Server 2016 SP2 (sys.dm_exec_input_buffer).   Rechte: VIEW SERVER STATE, ab SQL Server 2022 genügt VIEW SERVER PERFORMANCE STATE.   Achtung: Der letzte Befehl kann vertrauliche Werte enthalten.   OPTION (MAXDOP 1): Die Diagnose soll keine parallelen Worker belegen. */SELECT TOP (20)    DB_NAME(dt.database_id)                                         AS datenbank,    st.session_id                                                   AS sitzung,    s.status                                                        AS sitzungsstatus,    s.login_name                                                    AS anmeldung,    s.host_name                                                     AS rechner,    s.program_name                                                  AS programm,    dt.database_transaction_begin_time                              AS erster_logeintrag,    DATEDIFF(second, dt.database_transaction_begin_time, SYSDATETIME()) AS offen_s,    CAST(dt.database_transaction_log_bytes_used / 1048576.0 AS decimal(12, 1))     AS log_genutzt_mb,    CAST(dt.database_transaction_log_bytes_reserved / 1048576.0 AS decimal(12, 1)) AS log_reserviert_mb,    r.command                                                       AS laeuft_gerade,    REPLACE(REPLACE(LEFT(ib.event_info, 200), CHAR(13), N' '), CHAR(10), N' ') AS letzter_befehlFROM sys.dm_tran_database_transactions AS dtJOIN sys.dm_tran_session_transactions AS st ON st.transaction_id = dt.transaction_idJOIN sys.dm_exec_sessions AS s ON s.session_id = st.session_idLEFT JOIN sys.dm_exec_requests AS r ON r.session_id = st.session_idOUTER APPLY sys.dm_exec_input_buffer(st.session_id, NULL) AS ibWHERE dt.database_transaction_begin_time IS NOT NULL                -- hat schon ins Log geschrieben  AND st.session_id <> @@SPIDORDER BY dt.database_transaction_begin_timeOPTION (MAXDOP 1);

Im Lab fand sie die Sitzung sofort, SQL Server 2022, gekürzt:

Beispielausgabe
datenbank  sitzung  sitzungsstatus  programm  offen_s  log_genutzt_mb  letzter_befehl
HoldTx     54       sleeping        SQLCMD    9        .0              BEGIN TRAN; UPDATE dbo.Orders SET CustomerId = CustomerId + 1 WHERE OrderId = 1;

sleeping mit offener Transaktion heißt: Die Sitzung wartet auf ihre Anwendung, nicht auf SQL Server. Rechner, Programm und letzter Befehl zeigen, wo Sie nachfragen müssen. Der letzte Befehl ist der zuletzt gesendete Batch der Sitzung, nicht zwingend der, der die Transaktion begonnen hat. Transaktionen ohne Sitzung, etwa verwaiste verteilte Transaktionen, zeigt Abfrage 2 nicht; dafür hilft DBCC OPENTRAN in der betroffenen Datenbank.

Wie Sie die Transaktion beenden: Am besten durch die Anwendung, mit COMMIT oder ROLLBACK. Klären Sie vorher, was die Transaktion tut: ein vergessenes COMMIT, ein Ladeprozess, eine Indexwartung. Erst wenn die Anwendung es nicht kann, mit KILL <sitzung>. KILL rollt die Transaktion zurück, alle ihre Änderungen gehen verloren. Bei einer langen Transaktion kann das Rollback selbst lange dauern; KILL <sitzung> WITH STATUSONLY zeigt den Fortschritt. Microsoft rät, KILL mit äußerster Vorsicht einzusetzen. Im Lab war das Log nach KILL und einem Checkpoint wieder frei, belegt 0,1 bis 0,2 MB; auf SQL Server 2019 zeigte log_reuse_wait_desc noch bis zum nächsten Checkpoint ACTIVE_TRANSACTION. In FULL gibt erst die nächste Logsicherung den Platz frei.

REPLICATION: Replikation oder CDC liest das Log nicht ab

Transaktionale Replikation und Change Data Capture (CDC) lesen ihre Änderungen aus dem Log. Bis sie gelesen haben, bleibt der Abschnitt belegt. Läuft der Log Reader oder der CDC-Capture-Job nicht, wächst das Log, und zwar unabhängig vom Wiederherstellungsmodell, auch in SIMPLE.

Das wirkt zunächst schräg, denn SIMPLE soll das Log ja klein halten. Es ist aber so vorgesehen: SIMPLE erspart nur die Logsicherung. Für CDC schreibt Microsoft ausdrücklich, dass der Punkt, bis zu dem das Log freigegeben wird, auch in SIMPLE erst weiterrückt, wenn der Capture-Prozess alle Änderungen gelesen hat, und dass ein CHECKPOINT dann nichts freigibt. Für die Replikation folgt dasselbe aus Microsofts Beschreibung der Logarchitektur: Nicht ausgelieferte replizierte Transaktionen halten das Log in jedem Modell fest. Nur die Seite zu Fehler 9002 vermerkt beim Grund REPLICATION „Full recovery model only“; das passt nicht zu den übrigen Seiten. Im Lab haben wir CDC nachgestellt, nicht die transaktionale Replikation.

Im Lab haben wir CDC für eine Tabelle eingeschaltet, ohne dass der SQL Server Agent lief. Der Capture-Job konnte also nie starten, wie nach einem gestoppten Agent oder einem deaktivierten Job.

Nach 51 Einfügungen kam 9002 mit REPLICATION, die Datenbank stand auf SIMPLE. Den Capture-Lauf haben wir dann von Hand angestoßen (sys.sp_cdc_scan), so wie ihn der wieder gestartete Job ausführen würde. Bei vollem Log scheiterte er mit Meldung 18805 (The Log-Scan Process failed to construct a replicated command …), auf 2025 direkt mit 9002.

Hier war die Reihenfolge entscheidend. Der Capture-Lauf schreibt die Änderungen in die CDC-Tabellen und braucht dafür vermutlich selbst Log. Erst als das Log reichlich Platz zum Wachsen hatte, über eine zweite Logdatei ohne Größenbegrenzung, holte er auf, und das Log war frei. Mit 64 MB zusätzlichem Platz scheiterte er erneut mit 18805, obwohl das Log nicht voll war; die genaue Ursache haben wir nicht geklärt. Im Betrieb ist der Weg derselbe: erst Platz schaffen, dann den Agent oder den Capture- beziehungsweise Log-Reader-Job wieder starten und warten, bis er aufgeholt hat.

CDC bei vollem Log abzuschalten (sys.sp_cdc_disable_db), gab das Log ebenfalls frei, meldete auf 2017 bis 2022 aber Fehler 22831. Prüfen Sie danach is_cdc_enabled in sys.databases. Vor allem entfernt das Abschalten Änderungstabellen, Jobs und Metadaten, also auch bereits erfasste Änderungen, die noch niemand abgeholt hat. Das ist eine letzte Maßnahme, nur nach Rücksprache mit denen, die die Daten verwenden.

Weitere Gründe

WartegrundWas dahinterstehtWas hilft
AVAILABILITY_REPLICAEin sekundäres Replikat einer Availability Group hat die Logeinträge noch nicht festgeschrieben.Zustand und Rückstand prüfen. Ein ausgefallenes, getrenntes oder angehaltenes Replikat, das noch Mitglied der Gruppe ist, hält das Log unbegrenzt fest.
ACTIVE_BACKUP_OR_RESTOREEine Datensicherung oder Wiederherstellung läuft.Warten oder die Sicherung prüfen, die ungewöhnlich lange läuft.
CHECKPOINTSeit der letzten Freigabe gab es noch keinen Checkpoint.Meist kurz. Bleibt er stehen, einen CHECKPOINT in der Datenbank ausführen.
DATABASE_MIRRORINGDatenbankspiegelung ist angehalten oder hängt zurück.Spiegelung prüfen.
OLDEST_PAGEMit indirekten Checkpoints ist die älteste geänderte Seite älter als der Checkpoint.Meist kurz.
XTP_CHECKPOINTEin Checkpoint für In-Memory-OLTP steht aus.CHECKPOINT in der Datenbank.
LOG_SCAN, DATABASE_SNAPSHOT_CREATIONEin Lesen des Logs oder das Anlegen eines Snapshots läuft.Meist kurz.
NOTHINGNichts hält das Log fest.Ist es trotzdem voll, ist es zu klein für die größte Transaktion oder für die Last zwischen zwei Checkpoints.

Die Beschreibungen folgen der Microsoft-Dokumentation zu Fehler 9002. Im Lab haben wir LOG_BACKUP, ACTIVE_TRANSACTION und REPLICATION nachgestellt.

Sofort handeln, ohne Schaden anzurichten

Wenn die Anwendung steht, zählt jede Minute. Diese Reihenfolge hat sich bewährt:

  1. Abfrage 1 ausführen und den Wartegrund der betroffenen Datenbank notieren. Die Ausgabe sichern.
  2. Nach dem Grund handeln: LOG_BACKUP → Logsicherung. ACTIVE_TRANSACTION → Abfrage 2, Transaktion beenden lassen. REPLICATION → Log Reader oder CDC-Job. AVAILABILITY_REPLICA → Replikat.
  3. Wenn das nicht sofort geht und das Laufwerk Platz hat: die Logdatei mit SIZE vergrößern. Die Anwendung kann dann weiterarbeiten, während Sie den Grund beheben. SQL Server beschreibt neuen Logplatz vollständig mit Nullen; ein großer Schritt kann im Notfall Minuten dauern. Beginnen Sie mit einem Schritt, der sicher reicht, und setzen Sie danach MAXSIZE bewusst. Lag die neue Größe über der alten Höchstgröße, hob SQL Server MAXSIZE im Lab stillschweigend auf genau diese Größe an, die Datei konnte danach also nicht weiter wachsen.
-- Verschafft Luft, löst aber nicht den Grund. Größe und Name anpassen.ALTER DATABASE [IhreDatenbank] MODIFY FILE (NAME = N'IhreDatenbank_log', SIZE = 4096MB);-- Danach die Wachstumsgrenze bewusst setzen:ALTER DATABASE [IhreDatenbank] MODIFY FILE (NAME = N'IhreDatenbank_log', MAXSIZE = 16384MB);
  1. Ist das Laufwerk voll: vorübergehend eine zweite Logdatei auf einem anderen Laufwerk anlegen und sie wieder entfernen, sobald der Grund behoben ist. Microsoft beschreibt mehrere Logdateien ausdrücklich als vorübergehenden Zustand. In einer Availability Group, mit Log Shipping oder Spiegelung muss der Pfad auf allen Replikaten existieren und dort Platz sein, sonst wird die Datenbank auf dem Secondary angehalten. Dort ist SIZE auf der vorhandenen Datei der sicherere Weg, solange deren Laufwerk Platz hat.
-- Vorübergehend. Pfad, Größen und Name anpassen; mit Höchstgröße, damit nicht auch dieses Laufwerk vollläuft.ALTER DATABASE [IhreDatenbank] ADD LOG FILE (NAME = N'IhreDatenbank_log2',    FILENAME = N'Y:\Log\IhreDatenbank_log2.ldf', SIZE = 2048MB, FILEGROWTH = 512MB, MAXSIZE = 8192MB);

Wieder entfernen lässt sich die zweite Datei erst, wenn kein aktiver Teil des Logs mehr in ihr liegt. Im Lab scheiterte der erste Versuch auf allen Versionen mit Meldung 5042 (The file 'N3a_log2' cannot be removed because it is not empty.). Nach weiterem Betrieb, einer weiteren Logsicherung und einem Checkpoint gelang er. In sys.master_files stand die Datei danach noch mit Größe 0; laut Microsoft verschwindet der Eintrag mit der nächsten Logsicherung.

-- Erst entfernen, wenn die zweite Datei keine aktiven VLFs mehr hat (aktiv = 0), sonst Meldung 5042.SELECT file_id, COUNT(*) AS vlfs, SUM(CAST(vlf_active AS int)) AS aktivFROM sys.dm_db_log_info(DB_ID()) GROUP BY file_id;ALTER DATABASE [IhreDatenbank] REMOVE FILE [IhreDatenbank_log2];

Im Lab haben wir bei 100 % vollem Log und erreichter Höchstgröße von 64 MB drei Wege verglichen, je für LOG_BACKUP, ACTIVE_TRANSACTION und REPLICATION auf allen vier Versionen. Vergrößern mit SIZE und eine zweite Logdatei gelangen in 12 von 12 Fällen, danach konnte die Anwendung wieder schreiben. Nur MAXSIZE anzuheben, scheiterte in 10 von 12 Fällen selbst mit 9002, vermutlich weil auch diese Änderung ein paar Bytes Log braucht. Bei einem vollen Laufwerk statt erreichter Höchstgröße hilft MAXSIZE ohnehin nicht; diesen Fall haben wir nicht nachgestellt.

  1. Abfrage 1 wiederholen: Steht der Wartegrund wieder auf NOTHING, und sinkt belegt_prozent?

Was Sie nicht als Erstes tun sollten:

  • Verkleinern (Shrink). Solange etwas das Log festhält, gibt es nichts freizugeben. Im Lab lief DBCC SHRINKFILE bei vollem Log entweder ohne jede Wirkung durch oder scheiterte selbst mit 9002.
  • Auf SIMPLE umstellen. Bei vollem Log kann schon die Umstellung oder der danach nötige Checkpoint an 9002 scheitern; im Lab scheiterte ein CHECKPOINT bei vollem Log. Vor allem beendet SIMPLE die Logkette: Wiederherstellen lässt sich dann nur noch bis zur letzten Logsicherung. Nach dem Zurückstellen auf FULL braucht es sofort eine Voll- oder Differenzsicherung und wieder Logsicherungen, sonst bleibt die Datenbank unbemerkt ungeschützt. In einer Availability Group, mit Log Shipping oder Spiegelung ist SIMPLE nicht möglich. Bei ACTIVE_TRANSACTION und REPLICATION hilft es gar nicht.
  • Eine Logsicherung nach NUL. Sie gibt das Log frei, wirft die Sicherung aber weg und unterbricht die Logkette genauso.
  • Die Logdatei löschen oder die Datenbank ohne Log neu anhängen. Das kann die Datenbank inkonsistent machen. Es gibt keinen Fall von 9002, in dem das der richtige erste Schritt ist.
Notfall-Simulator: erst den Grund aus der Meldung wählen, dann eine Maßnahme. Ergebnisse aus dem PSG-Lab auf SQL Server 2017 bis 2025.

Die Datei danach auf eine sinnvolle Größe bringen

Nach dem Notfall ist die Logdatei oft viel größer als nötig. Einmalig zu verkleinern ist dann in Ordnung, wenn der Grund behoben ist und die Datei danach eine geplante Größe erhält. Im Lab:

Nach der Logsicherung und 20 weiteren Einfügungen folgten eine zweite Logsicherung und DBCC SHRINKFILE auf 8 MB. Auf allen Versionen kam dieselbe Meldung:

Beispielausgabe
Cannot shrink log file 2 (LogFull_log) because the logical log file located at the end of the file is in use.

Trotzdem wurde die Datei auf 2019 von 64 auf 26 MB kleiner, auf 2022 und 2025 auf 30 MB. Auf 2017 blieb sie bei 64 MB. Verkleinert wird nur bis zum letzten belegten Abschnitt. Liegt der am Ende der Datei, hilft erst die nächste Logsicherung und ein zweiter Versuch. Verkleinern Sie in Schritten auf die geplante Größe, nicht auf das Minimum, denn sonst muss die Datei im Betrieb sofort wieder wachsen.

Planen Sie die Größe so, dass die größte regelmäßige Transaktion und die Last zwischen zwei Logsicherungen hineinpassen, mit Reserve. Wachstum in festen Schritten in MB statt in Prozent hält die Zahl der virtuellen Logdateien (VLFs) im Rahmen. Viele kleine Wachstumsschritte erzeugen viele VLFs, und viele VLFs verlangsamen Start, Wiederherstellung und Replikation. Wie viele entstehen, hängt laut Microsoft von der Größe des Schritts im Verhältnis zur Datei ab, ab SQL Server 2022 nach einer geänderten Regel. Im Lab, jeweils bis gut 64 MB geschrieben:

WachstumLogdatei danachVLFs auf 2017, 2019, 2022 und 2025
Start 1 MB, Wachstum 1 MB73 MB100
Start 1 MB, Wachstum 64 MB129 MB12

In diesem Aufbau gab es keinen Unterschied zwischen den Versionen. Das überrascht: Microsoft beschreibt ab SQL Server 2022 eine geänderte Regel, nach der ein Wachstum bis 64 MB nur ein VLF erzeugt. Danach hätten es auf 2022 und 2025 weniger sein müssen; gezählt haben wir auf allen Versionen dieselbe Zahl, passend zur älteren Regel. Unabhängig davon zeigt die Tabelle, worauf es ankommt: kleine Schritte erzeugen ein Vielfaches an VLFs, hier achtmal so viele für etwa die halbe Größe.

Kleine Schritte: 100 statt 12 VLFs, bei 73 statt 129 MB.

Wachstum 1 MB: 100 VLFs für 73 MB

Wachstum 64 MB: 12 VLFs für 129 MB

Beide starten mit 1 MB und bekommen dieselbe Schreiblast, auf 2017, 2019, 2022 und 2025 gleich. Balken maßstäblich zur Dateigröße, VLFs schematisch gleich breit gezeichnet.

Virtuelle Logdateien nach dem Wachstum: kleine gegen große Wachstumsschritte, gemessen im PSG-Lab.

Damit es nicht wieder passiert

  • Logsicherungen im Takt Ihres Wiederherstellungsziels. Wer höchstens 15 Minuten Datenverlust verkraften kann, sichert das Log mindestens alle 15 Minuten. Das hält das Log zugleich klein.
  • Einen Alarm auf Abfrage 1. Ein Wartegrund, der länger als einige Minuten nicht NOTHING ist, eine Belegung über 80 % oder kann_wachsen = nein sind Frühwarnungen, lange bevor 9002 kommt.
  • Lange Transaktionen überwachen. Abfrage 2 zeigt, welche Sitzungen seit Minuten eine Transaktion offen halten.
  • Höchstgröße und Laufwerk zusammen denken. Eine MAXSIZE schützt das Laufwerk, führt aber genau zu 9002, wenn sie zu knapp ist.
  • Datenbanken in FULL prüfen: Gibt es für jede eine Logsicherung? Abfrage 1 meldet FULL ohne erste Vollsicherung eigens.

Genau diese Punkte gehören zu einem werktäglichen Systemcheck. Im PSG DBA Pool prüfen wir unter anderem Sicherungen, Jobs, Fehlerprotokoll und Speicherplatz, und ein SQL Server Health Check sieht sich Sicherungsketten und Wiederanlauf im Ganzen an.

Rechte für die beiden Abfragen

Abfrage 1 und 2 lesen Sichten für die ganze Instanz. Ohne Recht erhielt ein Benutzer im Lab Meldung 300, im Original:

Beispielausgabe
Msg 300, Level 14, State 1, Line 7
VIEW SERVER STATE permission was denied on object 'server', database 'master'.

So lautete sie auf SQL Server 2017 und 2019. Auf 2022 und 2025 nennt dieselbe Meldung VIEW SERVER PERFORMANCE STATE; dieses engere Recht genügte dort allein. Mit VIEW SERVER STATE lieferte Abfrage 1 alle Datenbanken, aber die Spalten zu Wachstum und Laufwerk blieben leer, und kann_wachsen zeigte „unbekannt (Recht fehlt)“. Der Grund: sys.master_files zeigt Dateien nur mit VIEW ANY DEFINITION (oder CREATE DATABASE, ALTER ANY DATABASE). Abfrage 2 braucht kein VIEW ANY DEFINITION; ab 2022 genügte für sie VIEW SERVER PERFORMANCE STATE allein. Für ein Überwachungskonto heißt das: VIEW SERVER STATE beziehungsweise ab 2022 VIEW SERVER PERFORMANCE STATE, dazu VIEW ANY DEFINITION. Die letzte Logsicherung liest Abfrage 1 aus msdb.dbo.backupset; das war im Lab für dasselbe Konto ohne weitere Rechte lesbar.

Häufige Fragen

Warum wird die .ldf-Datei nach der Logsicherung nicht kleiner? Weil die Logsicherung Platz im Log freigibt, nicht auf dem Laufwerk. Die Datei behält ihre Größe und wird beim nächsten Durchlauf wiederverwendet. Kleiner wird sie nur durch ein gezieltes Verkleinern, und das ist nur nötig, wenn sie nach einem Ausnahmefall viel zu groß ist.

Hilft eine Vollsicherung gegen ein volles Log? Nein. Sie gibt das Log nicht frei. Im Lab brach sie bei vollem Log in 6 von 24 Versuchen sogar mit 9002 ab. Die Logsicherung ist der richtige Schritt, sie gelang in allen 24 Versuchen.

Darf ich die Datenbank auf SIMPLE umstellen? Wenn für diese Datenbank keine Wiederherstellung auf einen Zeitpunkt gebraucht wird, ist SIMPLE eine bewusste und legitime Wahl. Als Notfallmaßnahme gegen 9002 kostet es die Logkette. Entscheiden Sie das nach Ihrem Wiederherstellungsziel, nicht nach dem Fehler.

Warum wächst das Log in SIMPLE? Weil auch dort eine offene Transaktion, Replikation, CDC oder eine sehr große einzelne Transaktion den Platz festhalten. SIMPLE erspart nur die Logsicherung.

Wie groß sollte das Log sein? Groß genug für die größte regelmäßige Transaktion, etwa eine Indexwartung oder einen Ladeprozess, und für die Last zwischen zwei Logsicherungen. Eine feste Faustregel nach Datenbankgröße gibt es nicht.

Und wenn TempDB voll ist? Das ist ein eigener Fall mit eigenen Ursachen, etwa dem Version Store. Der Beitrag Version Store und Log erklärt ihn.

Wenn es eilt

Steht die Anwendung, weil das Log voll ist, hilft unsere Akut-Hilfe. Für eine schnelle Einordnung helfen:

  • die Ausgabe von Abfrage 1, bei ACTIVE_TRANSACTION auch von Abfrage 2,
  • die genaue Fehlermeldung mit dem Grund in Anführungszeichen,
  • ob und wann Logsicherungen laufen und wohin sie schreiben.

Quellen

Weiterlesen: SQL Server Backup und Restore: die Grundlagen · Version Store und Log · SQL Server Query Store einrichten · Akut-Hilfe