How to Identify SQL Server Version from MDF/BAK Files: Technical Deep Dive


2 views

SQL Server database files (MDF) and backup files (BAK) contain metadata that reveals their origin version. The file header stores compatibility level information that directly correlates with SQL Server versions.

For MDF files attached to a SQL Server instance:

SELECT 
    name AS [Database Name],
    compatibility_level,
    SERVERPROPERTY('ProductVersion') AS [SQL Server Version],
    CASE compatibility_level
        WHEN 70 THEN 'SQL Server 7.0'
        WHEN 80 THEN 'SQL Server 2000'
        WHEN 90 THEN 'SQL Server 2005'
        WHEN 100 THEN 'SQL Server 2008/R2'
        WHEN 110 THEN 'SQL Server 2012'
        WHEN 120 THEN 'SQL Server 2014'
        WHEN 130 THEN 'SQL Server 2016'
        WHEN 140 THEN 'SQL Server 2017'
        WHEN 150 THEN 'SQL Server 2019'
        WHEN 160 THEN 'SQL Server 2022'
        ELSE 'Unknown version'
    END AS [Version Name]
FROM sys.databases
WHERE name = 'YourDatabaseName';

For backup files without restoring:

RESTORE HEADERONLY 
FROM DISK = 'C:\path\to\your\backup.bak';

-- The BackupSize and CompatibilityLevel columns reveal version info

For files not currently attached to SQL Server, examine the binary header:

-- PowerShell script to read first 100 bytes
$filePath = "C:\Data\Database.mdf"
$stream = [System.IO.File]::OpenRead($filePath)
$reader = New-Object System.IO.BinaryReader($stream)
$header = $reader.ReadBytes(100)
$stream.Close()

# Version signature appears at offset 0x60
$versionByte = $header[0x60]
"Detected SQL Server version signature: 0x{0:X2}" -f $versionByte
Hex Value SQL Server Version
0x62 SQL Server 2014 (12.x)
0x64 SQL Server 2016 (13.x)
0x66 SQL Server 2017 (14.x)
0x68 SQL Server 2019 (15.x)
0x6A SQL Server 2022 (16.x)

For comprehensive analysis, use DBCC PAGE command on attached databases:

DBCC TRACEON(3604);
DBCC PAGE(YourDatabaseName, 1, 0, 3);
DBCC TRACEOFF(3604);
  • Compatibility level doesn't always match the creating server version
  • Upgraded databases retain original version signatures
  • Compressed backups may obscure version information

The SQL Server database files (MDF) and backup files (BAK) contain metadata in their headers that reveals version information. This information is stored in a structure called the DBFILEHEADER which includes the version number used when creating the database.

For BAK files, you can extract version information using:

RESTORE HEADERONLY 
FROM DISK = 'C:\path\to\your\backup.bak'

The result set will include columns like SoftwareVersionMajor and SoftwareVersionMinor that indicate SQL Server version.

Here's a C# example to read the version from an MDF file header:

using (FileStream fs = new FileStream(@"C:\data\database.mdf", FileMode.Open))
{
    byte[] buffer = new byte[8192];
    fs.Read(buffer, 0, 8192);
    
    // Get version from offset 0x120 in the header
    short versionMajor = BitConverter.ToInt16(buffer, 0x120);
    short versionMinor = BitConverter.ToInt16(buffer, 0x122);
    
    Console.WriteLine($"SQL Server version: {versionMajor}.{versionMinor}");
}

Here are common SQL Server version numbers found in file headers:

  • SQL Server 2019: 15.x
  • SQL Server 2017: 14.x
  • SQL Server 2016: 13.x
  • SQL Server 2014: 12.x
  • SQL Server 2012: 11.x

If you can attach the database, running this command will show version information:

DBCC CHECKDB('YourDatabase') WITH NO_INFOMSGS;

Look for messages containing "Database version" in the output.

Remember these key points when working with database files:

  • Always work on copies of production files
  • Version detection might not work for very old SQL Server versions (pre-2005)
  • File headers might be corrupted in some cases
  • For encrypted databases, additional steps may be required

For quick version checks without attaching databases:

$filePath = "C:\Data\Database.mdf"
$header = New-Object byte[] 8192
$stream = [System.IO.File]::OpenRead($filePath)
$stream.Read($header, 0, 8192) | Out-Null
$stream.Close()

$major = [BitConverter]::ToInt16($header, 0x120)
$minor = [BitConverter]::ToInt16($header, 0x122)
Write-Host "SQL Server version: $major.$minor"