SQL Server Transaction Log Full

🚨Part of the SQL Server Errors series, the exact messages and what actually causes them.

Msg 9002  ·  Level 17  ·  State 2
The transaction log for database ‘YourDb’ is full due to ‘LOG_BACKUP’. Msg 9002, Level 17, State 2
Check log_reuse_wait_desc first: it names the actual blocker out of about a dozen possibilities, and the right fix follows from that name rather than from the message itself.

The important part of that message is the bit in quotes. LOG_BACKUP is not the problem, it is the diagnosis, and SQL Server has already told you which of about a dozen causes you have. Most advice online skips straight to shrinking the log, which fixes nothing and often makes the next outage worse.


Read the Reason, Not the Size

SELECT  name,
        log_reuse_wait_desc,
        recovery_model_desc,
        state_desc
FROM    sys.databases
WHERE   name = N'YourDb';

log_reuse_wait_desc is the answer. What it means:

ValueWhat is actually happeningWhat to do
LOG_BACKUPFULL recovery, no log backup has runTake a log backup. Not a full backup
ACTIVE_TRANSACTIONA transaction is still openFind it, see below
AVAILABILITY_REPLICAA secondary is behind, log cannot be truncatedFix replica sync
REPLICATIONLog reader agent has not read the logCheck replication
DATABASE_MIRRORINGMirror is behind or disconnectedCheck mirroring
CHECKPOINTSIMPLE recovery, checkpoint has not runUsually transient
NOTHINGLog can be reused, it is genuinely just too smallGrow the file

The Two Common Ones

LOG_BACKUP

The database is in FULL recovery and nobody is backing up the log. In FULL recovery, the log is only truncated by a log backup. A full backup does not do it, however many you take. This is the single most common cause of a full log.

BACKUP LOG [YourDb] TO DISK = N'D:\Backups\YourDb_log.trn';

Space becomes reusable immediately, the file does not shrink, but the space inside it is now free, which is what you want.

If the database does not need point-in-time recovery, the honest fix is to stop pretending it does:

ALTER DATABASE [YourDb] SET RECOVERY SIMPLE;

Do not do that on anything you would need to restore to a point in time. It breaks the log chain and your recovery point becomes the last full or differential backup. If in doubt, take log backups instead.

ACTIVE_TRANSACTION

Something has a transaction open and the log cannot be truncated past it. Find it:

SELECT  s.session_id,
        s.login_name,
        s.host_name,
        s.program_name,
        t.transaction_begin_time,
        DATEDIFF(MINUTE, t.transaction_begin_time, GETDATE()) AS open_minutes,
        r.status,
        r.command,
        SUBSTRING(qt.text, (r.statement_start_offset/2)+1, 4000) AS running_statement
FROM    sys.dm_tran_active_transactions t
JOIN    sys.dm_tran_session_transactions st ON st.transaction_id = t.transaction_id
JOIN    sys.dm_exec_sessions s ON s.session_id = st.session_id
LEFT JOIN sys.dm_exec_requests r ON r.session_id = s.session_id
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) qt
ORDER BY t.transaction_begin_time;

Look for an old transaction_begin_time and a session whose status is sleeping, that is an application that opened a transaction and never committed, usually because of an error path that missed its rollback. A sleeping session with an open transaction is the classic cause.

Also check for the oldest active transaction specifically:

DBCC OPENTRAN('YourDb');

Killing the session rolls the transaction back, and the rollback also needs log space and time, sometimes more than the original work. Understand what it was doing before you kill it.


Getting Out of It Right Now

If the log file is genuinely out of disk and you cannot back it up:

  • 1. Free disk space or add a second log file on another drive as a temporary measure:
    ALTER DATABASE [YourDb] ADD LOG FILE
        (NAME = N'YourDb_log2',
         FILENAME = N'E:\Logs\YourDb_log2.ldf',
         SIZE = 4GB);
  • 2. Take the log backup.
  • 3. Remove the temporary file afterwards, a permanent second log file is not a fix, it is a reminder of an incident.

Never use WITH TRUNCATE_ONLY or NO_LOG. They were removed for good reason: they break the log chain silently, so your next restore fails at exactly the moment you need it.


Why Shrinking Is Not the Fix

Shrinking the log after a backup will reclaim disk, but if the log grew to 40GB it grew for a reason, and it will grow again, this time in a hurry, during production, with autogrowth pauses.

Size the log for the workload’s peak and leave it there. A log at a stable large size is healthy. A log that shrinks and regrows repeatedly causes VLF fragmentation and stalls.


Stopping It Recurring

  • Log backups every 15 minutes on anything in FULL recovery. If a database does not deserve log backups, it does not deserve FULL recovery.
  • Alert on log percent used, not on disk full. By the time the disk is full you are already down.
  • Alert on transactions open longer than a few minutes. That catches the ACTIVE_TRANSACTION case before it becomes an outage.
  • Check log_reuse_wait_desc across all databases on a schedule, so you see the drift early.


Common Questions

I took a log backup and log_reuse_wait_desc still says LOG_BACKUP.
Two possibilities. The column reports what blocked reuse at the last attempt, so it can lag by a moment: query it again and see if it clears. If it does not, check whether the backup was copy only, because a copy only log backup writes a perfectly valid file and truncates nothing. Reproduced on a test database: the value read LOG_BACKUP before, stayed LOG_BACKUP after BACKUP LOG ... WITH COPY_ONLY, and only went to NOTHING after an ordinary log backup.
The log is full but log_reuse_wait_desc says NOTHING.
Then nothing is holding the log open and the file simply cannot get any bigger. That is one of three things: autogrowth is off, the file has reached its configured max size, or the volume is out of space. Check the growth and max size settings on the log file before you go hunting for a blocking transaction that is not there.
Can users still read while the log is full?
Yes. 9002 fails anything that has to write a log record, so inserts, updates, deletes and most DDL stop while SELECTs against committed data keep working. That is why the first sign is usually an application half working rather than an outage, and why nobody reports it until writes back up.
The wait says ACTIVE_TRANSACTION but DBCC OPENTRAN returns nothing.
The two are read at different moments. log_reuse_wait_desc reports the reason from the last time SQL Server tried to reuse the log, so a transaction that has since ended leaves a stale value behind while OPENTRAN, looking at the current state, correctly finds nothing. Re-check both. If the value persists with OPENTRAN still empty, look in sys.dm_tran_active_transactions for a prepared distributed transaction that never resolved.

Related Scripts

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *