SQL Optima guide
Backup verification beats backup theater
Restores you have never tested are hopes, not controls.
/*
================================================================================
Purpose: Reports the last full, differential, and transaction log backup
timestamps for all online user databases on the instance.
Provides: Recovery model, database state, last backup dates, hours since
last backup, and a calculated backup health status.
Importance: The most critical script for ensuring disaster recovery readiness,
meeting RPO/RTO SLAs, and data protection compliance.
Interpretation: Look for "CRITICAL" or "WARNING" in Backup_Status. Ensure log
backups are frequent (e.g., < 1hr) for FULL recovery databases.
Action: For databases with Backup_Status = "CRITICAL" (no backup within SLA), take an immediate backup:
BACKUP DATABASE [DBName] TO DISK = N'path';
For FULL recovery databases with long gaps since last log backup (< 1 hour is recommended), increase log backup frequency via a SQL Agent job. Schedule daily verification using this script in a monitoring job.
Criticality: Critical
Author: Ravi Sharma
================================================================================
*/
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET NOCOUNT ON;
WITH LastBackups AS (
SELECT
database_name,
MAX(CASE WHEN type = 'D' THEN backup_finish_date END) AS [Last_Full_Backup],
MAX(CASE WHEN type = 'I' THEN backup_finish_date END) AS [Last_Differential_Backup],
MAX(CASE WHEN type = 'L' THEN backup_finish_date END) AS [Last_Log_Backup],
MAX(backup_finish_date) AS [Last_Any_Backup]
FROM msdb.dbo.backupset WITH (NOLOCK)
GROUP BY database_name
)
SELECT
d.name AS [Database_Name],
d.recovery_model_desc AS [Recovery_Model],
d.state_desc AS [Database_State],
lb.Last_Full_Backup AS [Last_Full_Backup],
lb.Last_Differential_Backup AS [Last_Differential_Backup],
lb.Last_Log_Backup AS [Last_Log_Backup],
DATEDIFF(HOUR, lb.Last_Any_Backup, GETDATE()) AS [Hours_Since_Last_Backup],
CASE
WHEN d.state = 0 THEN -- ONLINE
CASE
WHEN lb.Last_Any_Backup IS NULL THEN 'CRITICAL: No backup ever found'
WHEN DATEDIFF(HOUR, lb.Last_Any_Backup, GETDATE()) > 48 THEN 'WARNING: Last backup > 48 hours ago'
WHEN d.recovery_model_desc = 'FULL' AND lb.Last_Log_Backup IS NULL THEN 'WARNING: Full recovery mode with no log backup'
WHEN d.recovery_model_desc = 'FULL' AND DATEDIFF(HOUR, lb.Last_Log_Backup, GETDATE()) > 24 THEN 'WARNING: Log backup > 24 hours old'
ELSE 'OK'
END
ELSE 'N/A (database not online)'
END AS [Backup_Status],
CAST('Backup verification audit. ' +
'Threshold: Full backups should be taken daily (or weekly for very large databases), log backups every 15-60 minutes for FULL recovery model. ' +
'Recommendation: Schedule regular full, differential, and log backups to meet RPO requirements. ' +
'Databases in FULL recovery model without recent log backups are at risk of massive log file growth and data loss.'
AS VARCHAR(1000)) AS [Metric_Context]
FROM sys.databases AS d WITH (NOLOCK)
LEFT JOIN LastBackups AS lb ON d.name = lb.database_name
WHERE d.database_id > 4 -- Exclude system databases
ORDER BY [Hours_Since_Last_Backup] DESC;
Review the full script and confirm the connected SQL Server instance before execution. The run instructions and output guide appear later in this article.
A green backup job only proves bytes left the instance.
Verification asks whether those bytes restore within RTO and whether the database comes online cleanly. SQLOptima Backup focuses on that confidence loop for production estates.
Why backup verification deserves a method
The central principle is that a completed backup job proves that a file was written, not that the database can be recovered. A single metric, recommendation, or successful command is not enough. The decision has to connect an observed symptom to a plausible cause, a controlled change, and a result that can be verified under the workload that matters.
Evidence to collect
Use evidence from the same time window whenever possible:
- backup history and chain continuity
- CHECKSUM and VERIFYONLY results
- restore duration against the RTO
- recovered data at the required point in time
A practical workflow
- Define the required restore scenario.
- Copy media to an isolated restore location.
- Restore full, differential, and log backups in order.
- Run integrity and application-level validation.
Common mistakes
Avoid these shortcuts:
- relying only on job success
- testing the latest full backup without the log chain
- never timing the restore
Verification and completion
Define completion before making the change. Confirm correctness first, then compare latency, throughput, reads, CPU, waits, storage behavior, or recovery time as appropriate for Backup verification beats backup theater. Test negative and boundary cases, not only the path expected to succeed. Watch the system long enough to cover the relevant workload pattern.
Download and run the diagnostic
Backup history and SLA review
Download backup_verification.sqlBefore you run it
- Run the script first on a non-production or read-only connection when possible.
- Review the complete SQL file before execution and confirm that the connected instance is the intended target.
- Required access: read access to msdb backup history and sys.databases.
- Open SQL Server Management Studio or Azure Data Studio, connect to the instance, open the downloaded file, and select Execute. Do not run diagnostic scripts through an application login.
- Save the result grid with the server name, collection time, and incident window. DMV output changes over time and often resets after a SQL Server restart.
What the script does
Shows the last full, differential, log, and any backup for every online user database, together with recovery model and a calculated health status. The download is intended for diagnosis and does not apply an automatic remediation. Read every statement anyway, especially when adapting the script for automation or a different SQL Server version.
How to read the output
Investigate CRITICAL and WARNING first. For FULL recovery databases, a missing or stale Last_Log_Backup threatens the recovery point and can prevent log truncation. This script checks history, not media readability; follow it with an isolated restore test.