The Log in This Backup Set Is Too Recent or Too Early to Apply (Errors 4305, 4326 and 3159)

🚨Part of the SQL Server Errors series, the exact messages and what actually causes them.In: Backup & Recovery

A restore has stopped, and the log backup you are holding will not apply to it. Which of these three messages you have decides what happens next.

⚡The second LSN in the message is where the database is right now. Restore the backup whose range contains it. 4305 means you skipped a file, 4326 means you are already past this one, and 3159 means take BACKUP LOG ... WITH NORECOVERY before you overwrite anything. None of the three is corruption.

All three come from the same rule. A log backup can only be applied if it starts at or before the point the database has reached, and ends after it. 4305 and 4326 are that rule failing in each direction, and SQL Server tells you both numbers it compared. 3159 is the same idea seen from the other end: the live database still holds log records that no backup has captured yet, and it will not let you overwrite them without being told to.

Nothing here needs a new backup or a support call. Every message and every LSN on this page is captured from a throwaway database on SQL Server 2025 (17.0.4075.5): one full backup, three log backups, then applied in the wrong order on purpose.


Read the Two LSNs in the Message

Every 4305 and 4326 carries two log sequence numbers. The first describes the file you tried to apply. The second is where the database currently sits, and the file you need is the one whose range contains it. Get the ranges from msdb:

SELECT  bs.backup_set_id,
        bs.type,                    -- D = full, I = differential, L = log
        bs.first_lsn,
        bs.last_lsn,
        bs.database_backup_lsn,     -- on a log: the full it chains from
        bs.backup_finish_date,
        bmf.physical_device_name
FROM    msdb.dbo.backupset AS bs
JOIN    msdb.dbo.backupmediafamily AS bmf ON bmf.media_set_id = bs.media_set_id
WHERE   bs.database_name = N'Sales'
ORDER BY bs.backup_finish_date;

This is the chain that produced the three messages on this page. Each log backup starts exactly where the previous one ended, which is what a healthy chain looks like:

type  first_lsn          last_lsn           database_backup_lsn  physical_device_name
D     44000000026400001  44000000028800001  0                    ...\Sales_full.bak
L     44000000026400001  44000000033600001  44000000026400001    ...\Sales_log1.trn
L     44000000033600001  44000000044000001  44000000026400001    ...\Sales_log2.trn
L     44000000044000001  44000000047200001  44000000026400001    ...\Sales_log3.trn

Line the message up against it. The 4305 says the database is at 44000000028800001, which is the end of the full backup, and the file that contains that LSN is Sales_log1.trn. The 4326 says the database is at 44000000044000001, the end of log 2, so the next file is log 3 and anything earlier is already in.

If the backups came from another server, msdb on this one knows nothing about them. Ask the files directly instead with RESTORE HEADERONLY FROM DISK = N'D:\Backups\Sales_log2.trn';, and the columns to read are FirstLSN, LastLSN and DatabaseBackupLSN.

And if you have lost track of what has already been applied to the restoring database, the last row in msdb.dbo.restorehistory for it, joined back to backupset, gives the same number the error message does:

SELECT TOP (1) rh.restore_date, rh.restore_type, bs.last_lsn AS database_is_now_at
FROM   msdb.dbo.restorehistory AS rh
JOIN   msdb.dbo.backupset AS bs ON bs.backup_set_id = rh.backup_set_id
WHERE  rh.destination_database_name = N'Sales'
ORDER BY rh.restore_date DESC, rh.restore_history_id DESC;

To check every database on the instance for gaps before an incident rather than during one, Get Backup Chain Integrity runs this reasoning across the whole of msdb.


4305: Too Recent, So a File Is Missing From the Sequence

Msg 4305  ·  Level 16  ·  State 1
The log in this backup set begins at LSN 44000000033600001, which is too recent to apply to the database. An earlier log backup that includes LSN 44000000028800001 can be restored. Msg 3013, Level 16, State 1 RESTORE LOG is terminating abnormally.

The file you applied starts after the point the database has reached. Something that covers the gap has not been applied yet. The capture was the simplest version: RESTORE DATABASE Sales FROM DISK = N'D:\Backups\Sales_full.bak' WITH NORECOVERY;, log 1 skipped, then RESTORE LOG Sales FROM DISK = N'D:\Backups\Sales_log2.trn' WITH NORECOVERY;, which raised the message above on Line 3.

The fix is to apply the file whose range contains the second LSN, then carry on in order. The database is untouched by the failure, so nothing has to be restarted:

RESTORE LOG Sales FROM DISK = N'D:\Backups\Sales_log1.trn' WITH NORECOVERY;
RESTORE LOG Sales FROM DISK = N'D:\Backups\Sales_log2.trn' WITH NORECOVERY;

The harder version is when the query against msdb shows a file you do not have. The usual reasons, in the order I would check them:

  • A differential was skipped. A log taken after a differential begins where the differential ends. Restore the differential, or every log between the full and that point.
  • Something else took a log backup. physical_device_name in the chain query names it. A second job, a third-party agent, or somebody running BACKUP LOG to shrink a file all break the sequence for everyone else, and their file is the one you now need.
  • The file was deleted or never copied. The row is in msdb, the path is gone.

If the missing file cannot be found anywhere, the chain is broken at that point. You can recover the database to the end of the last file you did apply, with RESTORE DATABASE Sales WITH RECOVERY, and lose everything after it. Or you start again from a full or differential taken after the gap, if one exists. There is no third option, and no amount of retrying changes the arithmetic.


4326: Too Early, So the Database Is Already Past This File

Msg 4326  ·  Level 16  ·  State 1
The log in this backup set terminates at LSN 44000000033600001, which is too early to apply to the database. A more recent log backup that includes LSN 44000000044000001 can be restored. Msg 3013, Level 16, State 1 RESTORE LOG is terminating abnormally.

The opposite direction. The file ends before the point the database has reached, so everything in it is already there. In the capture this was log 1 applied after log 2, RESTORE LOG Sales FROM DISK = N'D:\Backups\Sales_log1.trn' WITH NORECOVERY;, and the message above came back on Line 1.

Skip forward. The next file is the one whose first_lsn is at or below the second LSN and whose last_lsn is above it. Again the database is not damaged by the attempt, so continue from where you are.

When you did not apply anything out of order and still get 4326, the base is newer than the logs. That is the trap. A full or differential that was taken after the log backups you are holding has been restored, and every one of those logs is now too early. The same capture shows it: a second full backup taken later, restored as the base, then log 3 from the original chain. That raises the same Msg 4326, Level 16, State 1, this time saying the log terminates at LSN 44000000047200001 and that a more recent log backup that includes LSN 44000000079200001 can be restored.

Check database_backup_lsn on the log against checkpoint_lsn on the full you restored. If they differ, either go back to the older full that the logs chain from, or find the logs taken after the newer one. Restoring a full does not change which logs belong to it.

One thing that is not a 4326: applying the file you just applied a second time. On SQL Server 2025 that was accepted without a message, because the file’s range still contains the current position. Harmless, and worth knowing so you do not read a clean second pass as proof the chain is fine.


3159: Back Up the Tail Before You Overwrite

Msg 3159  ·  Level 16  ·  State 1
The tail of the log for the database "Sales" has not been backed up. Use BACKUP LOG WITH NORECOVERY to backup the log if it contains work you do not want to lose. Use the WITH REPLACE or WITH STOPAT clause of the RESTORE statement to just overwrite the contents of the log. Msg 3013, Level 16, State 1 RESTORE DATABASE is terminating abnormally.

This one fires on the target, not the file. The database you are restoring over is in FULL or BULK_LOGGED recovery and has log records since its last log backup. Those records are the tail, they exist nowhere else, and the restore will destroy them. SQL Server stops and asks. In the capture it was a plain restore of the full backup over the live database, RESTORE DATABASE Sales FROM DISK = N'D:\Backups\Sales_full.bak' WITH NORECOVERY;, and the message above came back on Line 1.

If the database is online, back the tail up with NORECOVERY. That captures the records and puts the database into RESTORING in one statement, so nothing can write to it between the tail backup and the restore:

BACKUP LOG Sales TO DISK = N'D:\Backups\Sales_tail.trn' WITH NORECOVERY, INIT;

Run the restore again and it goes through. The tail file is the last log you apply, after every scheduled log backup, and the row count at the end matched the live database exactly in testing. If the database is offline or will not start, Microsoft’s guidance is BACKUP LOG Sales TO DISK = N'D:\Backups\Sales_tail.trn' WITH NO_TRUNCATE, INIT; instead, and CONTINUE_AFTER_ERROR on a damaged database, which needs the log file itself to be intact. I did not have a way to damage the data file in the test, so that part rests on the documentation rather than on captured output.

WITH REPLACE is the other answer the message offers, and it is the right one only when you have already decided you do not want the tail. Refreshing a test copy from production, a restore test, a point in time you have chosen deliberately. It does exactly what it says. In the capture the live database had five rows, one of them written after the last log backup: SELECT COUNT(*) FROM Sales.dbo.Orders; returned 5, then RESTORE DATABASE Sales FROM DISK = N'D:\Backups\Sales_full2.bak' WITH REPLACE, RECOVERY; ran, and the same count returned 4.

The fifth row is gone, with no further warning. On a production database that is committed work somebody has already been told succeeded. REPLACE also waives the check behind error 3154, so it will happily overwrite a different database of the same name too. Take the tail backup. It costs seconds, and if it turns out you did not need it, nothing is lost by having it.


The Full Sequence, in Order

Every statement takes NORECOVERY except the last, and recovering is safest as its own statement at the end. Recover early by mistake and the database is usable but closed to further logs, and the only way to apply another file is to start again from the full.

-- 1. Capture the tail, only if the database exists and you want the work in it
BACKUP LOG Sales TO DISK = N'D:\Backups\Sales_tail.trn' WITH NORECOVERY, INIT;

-- 2. The base: the full, then the newest differential if you have one
RESTORE DATABASE Sales FROM DISK = N'D:\Backups\Sales_full.bak' WITH NORECOVERY;
RESTORE DATABASE Sales FROM DISK = N'D:\Backups\Sales_diff.bak' WITH NORECOVERY;

-- 3. Every log taken after that base, in backup_finish_date order
RESTORE LOG Sales FROM DISK = N'D:\Backups\Sales_log3.trn' WITH NORECOVERY;
RESTORE LOG Sales FROM DISK = N'D:\Backups\Sales_log4.trn' WITH NORECOVERY;

-- 4. The tail last, then recover
RESTORE LOG Sales FROM DISK = N'D:\Backups\Sales_tail.trn' WITH NORECOVERY;
RESTORE DATABASE Sales WITH RECOVERY;

A restore that stops part way leaves the database in RESTORING, which is its own message when somebody tries to open it. That is the correct state to be in between steps, not a problem to fix. And for a chain longer than a handful of files, have msdb write the statements rather than typing them: Generate Backup and Restore Scripts emits the whole sequence in order with the right options on each line.


When It Is Not This

MessageWhat it means, and the next move
3154 instead of any of theseA different database, not an ordering problem: error 3154
4330, recovery path is inconsistentA different recovery fork. Compare RecoveryForkID in RESTORE HEADERONLY
Every log too recent, begins_log_chain = 1The chain broke, usually SIMPLE and back. Base after it: what breaks the chain
3013 on its ownThe real error is the line above it: errors 3013 and 3241
4335, STOPAT time is too earlyStart again from the base, then STOPAT on the log that contains the time

Microsoft’s reference covers tail-log backups, including the NO_TRUNCATE and CONTINUE_AFTER_ERROR cases, and the ordering rules in Apply Transaction Log Backups in full.


Common Questions

Which file do I restore next?
The one whose LSN range contains the second number in the message. That number is where the database is right now. Run the msdb.dbo.backupset query in Read the Two LSNs and find the row where first_lsn is at or below it and last_lsn is above it. If no row qualifies, the file you need was never recorded here, or was deleted.
I only have the .trn files and no msdb history. How do I order them?
RESTORE HEADERONLY against each file returns FirstLSN, LastLSN and DatabaseBackupLSN without restoring anything. Sort by FirstLSN and each file’s LastLSN should equal the next file’s FirstLSN. A gap between two files is the missing backup.
Can I skip a log backup?
No. A log backup contains exactly the records between two LSNs and the next file starts where it ended, so a missing one is a hole nothing else fills. You can recover to the end of the last file before the gap, or start again from a full or differential taken after it. Those are the only two outcomes.
Is WITH REPLACE the fix for 3159?
Only if you have decided you do not want the work since the last log backup. It overwrites the tail without any further warning, which in testing turned a five-row table into a four-row one. For anything you care about, BACKUP LOG ... WITH NORECOVERY first, then restore, then apply that tail file last.
The tail-log backup fails because the data file is gone. Now what?
Microsoft’s documented route is BACKUP LOG ... WITH NO_TRUNCATE for an offline database, and CONTINUE_AFTER_ERROR on a damaged one, which can succeed only if the log file itself is intact. If neither works, every transaction since the last log backup is lost and the honest restore ends at that file.
I restored the same log twice and it worked. Is the chain wrong?
No. On SQL Server 2025 re-applying the file just applied is accepted silently, because its range still contains the database’s current position. It does no harm and proves nothing either way. 4326 only fires when the whole file is behind the current position.
Does a differential change the order?
It shortens it. Restore the full, then the newest differential, then only the logs taken after that differential. The logs between the full and the differential are already inside the differential, and applying one of them after it raises 4326.

Comments

Leave a Reply

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