SQL Server Error 825: read-retry succeeded and the disk is failing

Error 825 is what SQL Server writes to the error log when a disk read failed on the first attempt but succeeded on a retry (attempt 2, 3, or 4). The query completes. The application sees no failure. But the storage underneath just told you it is failing.

Most monitoring setups never surface Error 825. It is a severity-10 informational message, and typical SQL Server Agent alert configurations target severity 19 and above. The error sits quietly in the log until something harder arrives: an 823 (hard I/O error) or an 824 (logical consistency error). By then the page may already be unreadable.

Treat every Error 825 as a page. The read worked this time, but the same sector, controller, or path will eventually return a hard failure. The job now is to identify which file, which volume, and which underlying component is deteriorating before the next read does not recover.

What this means

When SQL Server issues a read, the SQLOS I/O subsystem hands it to the operating system. If the OS returns a failure (bad sector, controller timeout, transport error), SQL Server does not immediately surface it. The engine retries the read up to four times before declaring a hard 823 or 824. If any retry succeeds, the page is returned to the buffer pool, the query continues, and Error 825 is written to the error log.

The message text looks like this:

Error: 825, Severity: 10, State: N.
A read of the file '<path>' at offset <n> succeeded after failing <N> time(s) with error: <OS error text>.
Additional messages in the SQL Server error log and system event log may provide more detail.
This error condition threatens database integrity and must be corrected.
Complete a full database consistency check (DBCC CHECKDB).

Severity 10 is the key gotcha. Microsoft classifies severities 0 through 10 as informational. They do not raise exceptions that flow into TRY…CATCH blocks, and they do not trigger default SQL Server Agent alerts. Without an explicit message_id-based alert on 825, the warning is invisible to operations.

This behavior has not changed since Error 825 was introduced in SQL Server 2005. The same read-retry path, the same severity, and the same alerting gap apply to every currently supported version through SQL Server 2025.

Common causes

CauseWhat it looks likeFirst thing to check
Failing disk sector825 on one file at one offset; OS event log reports bad blockssp_readerrorlog 0, 1, 'Error: 825' and the OS system event log
SAN or storage controller degradation825 across multiple files on the same LUN; latency spikes on the affected filesPer-file I/O stall deltas during the 825 window
HBA, fabric, or cabling fault825 entries clustered in time, possibly with link resets in the OS event logOS event log around the 825 timestamp
Storage firmware bug or MPIO path thrashing825 spikes during array rebalance, path failover, or firmware updatesStorage array logs; correlate with maintenance windows
Cloud disk throttling or transient fault825 on cloud VM storage during IOPS or throughput cap burstsCloud provider throttle metrics for the disk tier
Corrupt page on otherwise healthy media825 followed by an 824 on the same page idmsdb.dbo.suspect_pages for that database and page

Quick checks

Run these in order. All are read-only.

-- 1. Find every 825 in the current error log
EXEC sp_readerrorlog 0, 1, 'Error: 825';

-- 2. Search the most recent archived log if the event rolled over
EXEC sp_readerrorlog 1, 1, 'Error: 825';

-- 3. Check for harder I/O errors in the same window
EXEC sp_readerrorlog 0, 1, 'Error: 823';
EXEC sp_readerrorlog 0, 1, 'Error: 824';

-- 4. Check the suspect_pages table for active corruption records
SELECT database_id, DB_NAME(database_id) AS database_name,
       file_id, page_id, event_type, error_count, last_update_date
FROM msdb.dbo.suspect_pages
WHERE event_type IN (1, 2, 3)
ORDER BY last_update_date DESC;

-- 5. Map each database file to its volume and per-file I/O stall
SELECT
    DB_NAME(vfs.database_id) AS db,
    mf.name AS file_name,
    mf.type_desc,
    mf.physical_name,
    vs.volume_mount_point,
    vfs.io_stall_read_ms,
    vfs.num_of_reads,
    CASE WHEN vfs.num_of_reads > 0
         THEN vfs.io_stall_read_ms * 1.0 / vfs.num_of_reads
         ELSE 0 END AS avg_read_latency_ms,
    vs.available_bytes * 1.0 / vs.total_bytes AS pct_free
FROM sys.dm_io_virtual_file_stats(NULL, NULL) vfs
JOIN sys.master_files mf
    ON vfs.database_id = mf.database_id AND vfs.file_id = mf.file_id
CROSS APPLY sys.dm_os_volume_stats(mf.database_id, mf.file_id) vs
ORDER BY vfs.io_stall_read_ms + vfs.io_stall_write_ms DESC;

How to diagnose it

Goal: identify which file, which volume, and which storage component produced the 825, and confirm whether any page is already damaged.

  1. Capture the 825 entries with timestamps and offsets. Run sp_readerrorlog 0, 1, 'Error: 825'. Each row includes the physical file path, the byte offset, the retry count, and the OS error text. Record the file, the offset, and the time window.

  2. Correlate with sys.dm_io_virtual_file_stats. Snapshot the DMV, wait a measured interval, snapshot again, compute deltas per file. The file named in the 825 should show disproportionate io_stall_read_ms growth relative to its read count. Compare average read latency against known thresholds: under 10ms excellent, 10-20ms acceptable, over 20ms degraded, over 50ms severe.

  3. Check msdb.dbo.suspect_pages. The table records pages that hit an 823 or 824. Error 825 is a success-after-retry, so a clean retry may not add a row. An empty suspect_pages does not rule out active storage degradation. Any new row is a page-level alarm on its own. The table retains a maximum of 1000 rows; older entries are purged automatically, so new events may displace uninvestigated old ones.

  4. Run DBCC CHECKDB against the database named in the 825. CHECKDB is I/O-intensive and creates an internal database snapshot that consumes TempDB space, so schedule it carefully. CHECKDB can return clean even when 825 is firing, because the retry path may deliver a correct page on a later attempt. A clean CHECKDB does not contradict an 825. Run it anyway: if a page is already torn or checksum-failed, this is where it surfaces.

  5. Pull the OS system event log for the same window. Storage subsystems usually log the underlying error before SQL Server does. Look for bad-block events, controller resets, MPIO path failovers, or disk firmware messages.

  6. Check for 825 clustering. A single 825 is a warning. A rising rate, several per hour, then several per minute, is a failing component. Trend the count over hours and days. Increasing frequency toward a hard 823 or 824 is the classic signature of SAN controller failure or deteriorating cabling.

  7. Correlate with backup health. 825 events frequently appear alongside backup failures (Msg 3203, Msg 2013) when the storage cannot deliver a clean read of a data file. If backups started failing around the same time, treat the storage subsystem as the prime suspect.

flowchart TD
    A[OS read fails] --> B[SQLOS retries up to 4 times]
    B -->|retry ok| C[Error 825 written
query completes] B -->|all retries fail| D[Error 823 or 824
page unreadable] C --> E[Invisible to default
SQL Agent alerts] E --> F[Investigate file, offset,
OS error, suspect_pages] F --> G{I/O stalls and
suspect_pages correlate?} G -->|yes| H[Storage degradation
confirmed] G -->|no| I[Watch frequency
trend]

Metrics and signals to monitor

SignalWhy it mattersWarning sign
Error 825 in error logEarliest reliable indicator of failing storageAny nonzero count in a window
Error 823 (hard I/O error)Read failed all retries; page may be unreadableAny occurrence is PAGE
Error 824 (logical consistency)Checksum or torn page detected after readAny occurrence is PAGE
msdb.dbo.suspect_pages rowsDurable record of pages that hit I/O errorsNew row since last check
Per-file io_stall_read_ms deltaSQL Server’s direct view of storage latencySustained average read latency above 20ms
Per-file io_stall_write_ms delta (log files)Log write latency directly impacts every commitSustained log write latency above 5ms
PAGEIOLATCH_* wait timeWorkers blocked waiting for physical readsRising share of total wait time
Backup job failuresStorage cannot deliver clean reads for backupMsg 3203 in job output
OS storage event logUnderlying controller, disk, and path errorsBad-block, path-reset, firmware events
Error 825 frequency trendPredicts escalation to a hard 823 or 824Count increasing over consecutive windows

Fixes

Error 825 is not a SQL Server configuration problem. The engine is reporting a storage problem. The fixes live below SQL Server.

Contain the risk immediately

  1. Take a full backup before the failing read becomes an unreadable read. A backup taken now is the best recovery point you will have. Verify it with RESTORE VERIFYONLY. If the backup fails with bad-block errors, you have just confirmed a hard storage fault.
  2. Identify and isolate the affected file and volume. If only one database file is on the deteriorating volume, consider whether you can fail over to a secondary (AlwaysOn) or restore the database to a different volume. Do not wait for the next 823.
  3. Engage the storage or hypervisor team. Provide them with the file path, offset, OS error text, and timestamp from the 825 entry. They have visibility into array, controller, and disk health that SQL Server does not.

Address the storage component

  1. Run vendor storage diagnostics against the LUN. Most arrays have a read-only surface scan or SMART-style check that can identify the failing sector without disrupting I/O.
  2. Replace the failing component. Disk, HBA, cable, or controller. Do not assume a single bad sector is isolated; on enterprise storage, a bad sector often indicates a failing disk surface or a degraded controller cache battery.
  3. On cloud storage, reattach the disk to a different host or upgrade the disk tier. Throttling-induced 825 errors on cloud VMs indicate you have hit an IOPS or throughput cap for too long. Moving to a higher tier or spreading I/O across additional disks is the structural fix.

Establish a recovery safety net

  1. Pre-stage a tested restore path. The only way to know your backups are valid is to restore them. Schedule regular restore tests, not just RESTORE VERIFYONLY.
  2. Maintain a baseline of per-file I/O latency. Without a baseline, you cannot tell whether a 15ms average read is normal for that volume or a recent regression.
  3. Confirm PAGE_VERIFY CHECKSUM is enabled on every user database. When the storage does deliver a corrupt page, checksums let SQL Server detect it via Error 824 instead of silently returning wrong data.

Prevention

  • Alert on message_id 825 directly. The default SQL Server Agent alert configuration uses severity thresholds that will never fire on a severity-10 message. Add an alert scoped to @message_id = 825, @severity = 0. The standard reference for this is Brent Ozar’s SQL Server alert script, which includes 825 alongside 823 and 824.
  • Treat any 825 as a page. Severity 10 means informational in the documentation, but operationally it means the storage just failed a read and got lucky. Page on the first occurrence, not the tenth.
  • Keep CHECKDB on a weekly schedule for production databases. Some corruption modes are only detected by CHECKDB. Error 825 may precede them by days or weeks.
  • Track suspect_pages over time. Investigate every new row. Manually remove resolved entries once investigated so new ones are obvious. The 1000-row cap means old entries are silently displaced.
  • Snapshot sys.dm_io_virtual_file_stats externally. The DMV is cumulative since instance startup. Without periodic external sampling, you have no delta to compare against when 825 fires.

How Netdata helps

  • Per-second error log scraping surfaces the first 825 within the same minute it is written, before the next read becomes an unrecoverable 823. Default severity-based alerting misses it; explicit message_id tracking does not.
  • Per-file I/O stall correlation (io_stall_read_ms and io_stall_write_ms deltas) lets you confirm that the file named in the 825 is also the file with climbing latency, ruling out random transient reads.
  • PAGEIOLATCH_* wait time trends show whether storage degradation is starting to block workers, which is the path from soft warning to users reporting the database is slow.
  • suspect_pages row count monitoring catches the moment a soft 825 escalates to a hard 824 and a row lands in msdb.
  • Backup job and duration trending flags the backup failures that often accompany 825 events, before someone needs a restore that does not exist.

Netdata’s Microsoft SQL Server monitoring brings these signals together with per-second metrics and ML anomaly detection.