SUBMIT A FILE TYPE CONTACT US SUPPORT ABOUT US

What Is an MDF File? A Database Made of Pages, and What Happens When Pages Break

An MDF file is a SQL Server data file, so copy it before you attach it. Jump to your question below, or work through it in order.

44 min read Updated October 2026 Checked against sources and tests

What Is an MDF File? The primary data file of a SQL Server database, and two other things with the same ending

Short answer

An MDF file is the primary data file of a Microsoft SQL Server database. It stores the tables, indexes and rows in pages of 8,192 bytes, and Microsoft recommends the .mdf ending for it. The same three letters also name an Alcohol 120% disc image and an ASAM measurement file.

We read 4 public MDF files, and we damaged them in 19 ways to make 132 copies. Our 64 line script flagged 94 copies. The other 38 got no flag, and 21 of them had changed data pages. The file command said data on all 132.

To see the parts, go to the inside part. To check an MDF file, follow the six steps. To judge risk, read the safety part.

An MDF file is the primary data file of a Microsoft SQL Server database, and its name ends in .mdf. It stores the tables, indexes and rows of one database in pages of 8,192 bytes. SQL Server writes the LDF log file beside it.

Microsoft’s page on database files says every database has one primary data file. It says the MDF file contains startup information for the database and points to the other files. Microsoft recommends .mdf for it, .ndf for secondary data files and .ldf for transaction logs.

The word is recommends. The page names no rule. One Microsoft Q&A answer says a file with the .mdf ending can be a secondary data file or not a SQL Server file at all. The ending is a hint, and the first bytes give the proof.

Three kinds of file share the .mdf ending

Wikipedia’s page for MDF lists three meanings. They are the Master Database File of SQL Server, the Media Descriptor File of Alcohol 120% and the Measurement Data Format of ASAM. FileInfo’s page adds a fourth, a translation memory file from Trados.

Three kinds of MDF file
Meaning What it is and where it comes from
SQL Server data file The primary data file of a database. This page covers it, and all 4 of our public MDF files are of this kind.
Alcohol 120% disc image A disc image. PRONOM says Alcohol 120% creates it, and it lists a sidecar file with the ending .mds.
ASAM measurement data A binary format for recorded or calculated data, says ASAM. ASAM’s wiki names the ending .mf4, and FileInfo lists the Vector entry under .mdf.

We read no disc image and no ASAM file, so this page says nothing about their insides. Two facts separate a SQL Server file from the others. The size is a multiple of 8,192 bytes, and the first four bytes are 01 0F 00 00. All 4 of our MDF files pass both.

Where our MDF files come from

We read four public MDF files. Two are copies of Northwind.MDF from two sample projects, one is NORTHWND.MDF and one is AdventureWorks2014_Data.mdf. Northwind and AdventureWorks are the sample databases of a fictitious trading company and a fictitious bicycle maker. They contain no private data.

The four MDF files add up to 227,934,208 bytes, 27,824 pages and 1,117,259 rows. We copied one of them and called it northwind.mdf. It has 432 pages and 7,201 rows. We damaged all four MDF files in 19 ways. That gave 132 damaged copies.

We read every MDF file with our own scripts and with the file command 5.45. We used Python 3.13 and xxd. We did not start SQL Server and we did not attach a file, so what we say about attaching comes from Microsoft’s pages.

MDF file facts at a glance

Quick facts about MDF files
Property Value
Meaning The primary data file of a SQL Server database. It stores tables, indexes and rows.
Made by SQL Server, or LocalDB, the developer edition of the engine. Any server that creates a database writes one.
Format Binary, in pages of 8,192 bytes. Microsoft documents the page types and the 96 byte page header.
Start The bytes 01 0F 00 00, the header of page 0. All 4 of our public MDF files start that way.
Version Two numbers in the boot page, page 9. Our files show 655, 782 and 904.
Size A multiple of 8,192 bytes. Ours range from 3,538,944 to 215,220,224 bytes.
Opens with SQL Server, which attaches it. Free viewers from SysTools and Freeviewer read it without a server.
Companion files An LDF log file, and sometimes NDF files. All data files must be available to attach.
Our tests 4 public MDF files, 132 damaged copies, our 64 line script and a 26 line row counter.

Wrong page? Look at the LDF page for the SQL Server log file, the MDB page for Access databases or the SQLITE page for SQLite databases.

What Is Inside an MDF File? Pages of 8,192 bytes, a file header on page 0 and a boot page on page 9

An MDF file is a list of pages of 8,192 bytes. Page 0 is the file header and page 9 is the boot page. Every page starts with a 96 byte header that names its type, its own number and its protection value.

The figure cuts our 3,538,944 byte sample into its 432 pages and colors them by type. Under it are six notes on the parts. The first 32 bytes of the MDF file follow in the code box.

A strip of 432 pages of Northwind.MDF colored by type, with a legend of counts and six notes on the file header, the allocation maps, the boot page, data pages, the page header and empty pages.
Figure 1. The 432 pages of one MDF file, colored by type.
The first 32 bytes of our MDF file, shown by xxd
00000000: 010f 0000 0801 0000 0000 0000 0000 0000  ................
00000010: 0000 0000 0000 0100 6300 0000 6a1b 9404  ........c...j...

The file header page

Page 0 is the file header page. Paul Randal’s note on file header pages says it is the first page of the MDF file and the place for the metadata about the MDF file. Byte 0 is 01 and byte 1 is 0F, which is type 15. Bytes 2 and 3 are zero.

So 01 0F 00 00 is the start of a page header and not a signature that Microsoft documents. It is the same in all 4 of our MDF files, and the check part uses it. Bytes 4 and 5 are flag bits. In our MDF files they show whether a page uses torn page bits or a checksum.

The 96 byte page header

Microsoft’s guide to pages says every page begins with a 96 byte header. Paul Randal’s article on the anatomy of a page names the fields. We read the offsets from our MDF files. Byte 1 is the page type, bytes 22 and 23 count the rows and bytes 24 to 27 name the table by number.

Bytes 32 to 37 give the file and page number the page claims to be. Bytes 58 and 59 count ghost rows, which are rows that a delete has marked. Bytes 60 to 63 are the checksum or the torn page bits. Our script reads all of these.

Page types and the allocation maps

Type 1 is a data page, type 2 an index page and type 3 a text page for long values. Type 10 is an IAM page, which lists the extents of one table or index. Type 11 is a PFS page, which says which pages are in use. Types 8 and 9 are the GAM and SGAM maps.

Types 16 and 17 are the differential map and the bulk change map, which Microsoft calls DCM and BCM. Type 13 is the boot page and type 15 the file header. Our AdventureWorks file also has 4 pages of type 4, which we did not study.

In our MDF files the PFS page is page 1, the GAM page is page 2 and the SGAM page is page 3. The differential map is page 6 and the bulk change map is page 7. A new PFS page comes every 8,088 pages, so AdventureWorks has 4 of them.

The boot page

Page 9 is the boot page. Paul Randal’s note on boot pages says every database has one boot page with critical information about the database. It is always page 9 of the first file. Bytes 100 and 101 give the database version, and bytes 102 and 103 give the version that created it.

In our sample the first number is 655 and the second is 539. The versions part explains them. Microsoft documents neither offset, so we checked them against all four MDF files and against the numbers that Microsoft and Wikipedia list.

Data pages, rows and empty pages

Page 205 of our sample is a data page with 42 rows, and the table is object 21575115. That table is Orders, which has 830 rows in all. Our 26 line script adds up the row counts of the data pages that the PFS page marks as in use, and it prints 7,201 rows for the MDF file.

22 pages of our sample are all zeros. 21 more are not in use and still contain old content, and in AdventureWorks the numbers are 750 and 2,578. A page that the PFS page marks as free can contain old data, so our checks read only the pages that are in use.

What Microsoft says about the limits

A single row can use 8,060 bytes of data and overhead on a page, says Microsoft. Eight pages make an extent of 64 KiB. Paul Randal says in a reply that 8,096 bytes is the space for data on a page, so 8,060 is the limit of one row and not of one page.

We read this layout from four public MDF files and the pages named above. We did not start SQL Server, so it can read some of these parts in other ways. Microsoft documents the page types and the header, and we found the byte offsets ourselves.

Which SQL Server Versions Write MDF Files? Two numbers in the boot page name the version

The boot page has two version numbers, one for the database and one for the version that created it. Our four MDF files show the versions 655, 782 and 904. Their creation versions are 539 and 782.

The figure lists eleven numbers and the SQL Server release that goes with every one. The last column marks which numbers our four MDF files use. Northwind was made on SQL Server 2000, and NORTHWND.MDF and AdventureWorks have newer numbers.

A table of the database version numbers from 539 for SQL Server 2000 to 998 for SQL Server 2025, with the rows that our four MDF files use marked.
Figure 2. The database version numbers and the files that use them.

Where the numbers come from

Wikipedia’s history of SQL Server has a column for the internal database version. Microsoft’s page for the sysdatabases view defines the column and lists no values. It calls the value informational, not supported and not guaranteed for the future.

SQL Server 2019 is the weak spot. Wikipedia lists 895, and one Microsoft Q&A answer about version 904 says a database of version 904 was created on SQL Server 2019. Our AdventureWorks file says 904. We could not settle it, so the figure shows both.

A newer file cannot go to an older server

Microsoft says a database created by any more recent version of SQL Server can’t be attached in earlier versions. The error is number 948, and its text names both versions. One Q&A thread shows a server that supports version 852 and earlier refusing a file of version 904.

Another thread shows a file of version 957 refused by a server that accepts 904 or earlier. Microsoft’s page on error 948 gives the message and lists no numbers. Read byte 100 of page 9 before you choose a server.

Attaching upgrades the MDF file

Microsoft’s page on attaching says the database is automatically upgraded to the internal version level of the new instance. The upgrade page says this prevents the database from being used with an older version. Keep a copy before you attach.

That fits what we see. Our AdventureWorks file has version 904 and creation version 782, which suggests a file made on SQL Server 2014 and then attached to any newer server. Microsoft says compatibility level stays where it was after the upgrade.

What this means for your MDF file

Read the two numbers of an MDF file before you choose a server. A file with a higher number than your server supports will not attach, and a file that attaches is changed for good. Our script prints an error for a version it does not know.

The version is also the first thing that damage changes in the boot page. The damaged part shows what our script says when a copy has the version 999.

What Do Four Public MDF Files Contain? 1,117,259 rows, no flags and two kinds of page protection

We read 4 public MDF files. They have 27,824 pages and 1,117,259 rows. Our script flagged none of them, and our row counter printed the same totals every time we read a file.

Two files are copies of Northwind.MDF, and they differ by 9 rows. The others are NORTHWND.MDF and the data file of AdventureWorks 2014. They are public sample databases, so they show a test set and not every MDF file you can find. The table lists what every MDF file contains.

4 public MDF files
1,117,259 rows to count
227.9 MB of data to read
132 damaged copies
The four public MDF files
File What we found
Northwind.MDF, first copy Version 655, created as 539. 3,538,944 bytes, 432 pages, 7,201 rows in 38 objects. Torn page bits protect the pages.
Northwind.MDF, second copy The same version and size, and another hash. 7,192 rows in 38 objects. Torn page bits protect the pages.
NORTHWND.MDF Version 782, created as 539. 5,636,096 bytes, 688 pages, 11,069 rows in 40 objects. Torn page bits protect the pages.
AdventureWorks2014_Data.mdf Version 904, created as 782. 215,220,224 bytes, 26,272 pages, 1,091,797 rows in 116 objects. A checksum protects the pages.

What the four MDF files show

Three files use torn page bits and AdventureWorks uses a checksum. Microsoft’s page on PAGE_VERIFY says CHECKSUM calculates a value over the page contents. It says TORN_PAGE_DETECTION saves a 2 bit pattern for every 512 byte sector of the page.

All pages in use have the protection value in all four MDF files, except page 7 and page 12. Page 7 is the bulk change map and page 12 is an IAM page. Our script checks the value on every page that the PFS page marks as in use.

The MDF files also contain old pages. In the first Northwind copy, 22 pages are all zeros and 21 are not in use but still have content. In AdventureWorks the numbers are 750 and 2,578. We read only the pages in use, because old content in free space would give false alarms.

What the scripts did with the MDF files

Our 64 line script flagged none of the four MDF files. It read AdventureWorks, which has 26,272 pages and 215 MB, in 2.4 seconds. The three small files took less than a tenth of a second. Our 26 line row counter read all four in under a second.

The file command said data on all four intact MDF files. It has no rule for MDF files, so it gave no hint of the type in any test. That is a low bar for our script, because we tuned its rules on these MDF files, so we tested it on damaged copies as well.

The 132 damaged copies

Every file got 33 damaged copies in 19 kinds. A kind that picks a random page got more copies, so the kinds have 4, 12 or 16 copies in all. We fixed the random seed by file and copy number, so anyone can make the same copies.

Four public MDF files with their version, size, pages and page check, and a bar for every file that splits 33 damaged copies by what changed and whether our script flagged it.
Figure 3. Four public MDF files and what 33 damaged copies of every file showed.

Every bar splits the 33 copies of one file into four groups. The three files with torn page bits got the same split. AdventureWorks has no silent copies where data pages changed, because its checksum caught every changed byte.

A checksum sees more AdventureWorks had no silent copy with changed data pages. Every one of the three torn bit files had 7.
Some copies said nothing 38 of the 132 copies got no flag from our script, and 21 of them had changed data pages.
The file command saw nothing It said data on all 132 copies, and it said data on the four intact MDF files too.
Size did not decide Zeroing 5 percent of the data pages of AdventureWorks cost 53,012 of its 1,091,797 rows.

What the numbers do not show about MDF files

We did not start SQL Server, so we cannot say what an instance does with our damaged copies. A server can refuse a file that our script accepts, and it can repair a page that our script flags. We tested four MDF files from three projects and no encrypted file.

What Happens When an MDF File Is Damaged? 132 copies, and 38 that got no flag from our script

We damaged 4 MDF files in 19 ways and read all 132 copies. Our script flagged 94 copies and gave no flag to 38. 21 of those 38 had changed data pages, and the row counter printed the same totals on all 21.

We changed one thing in a file at a time and sorted the 19 kinds into five groups. They cover the header and boot page, cut files, allocation pages, full pages and single bytes. We skipped the last byte of every 512 byte sector, because torn page bits live there.

We read every copy with our 64 line script and our 26 line row counter. A flag is any line that the script printed about a problem. A name like k12.mdf in the code box is a copy of kind 12 in the figure. We changed data pages in 72 copies.

A grid of 19 kinds of damage in five groups, with a bar for every kind that splits the damaged copies into four outcomes, plus counts of copies with a flag and copies with the same row totals.
Figure 4. 132 damaged copies in 19 kinds, and what our script and row counter said.

Green means the script flagged a change to data pages. Blue means it flagged a change to other pages. Red means data pages changed and the script said nothing. Gray means other pages changed and the script said nothing. The last two columns count flags and same row totals.

Silent damage in an MDF file

38 copies got no flag. 21 of them have one changed byte in a data page, 17 have another change that data pages do not show. All 21 are in the three files with torn page bits. A torn page check cannot see one changed byte, because it compares 2 bits of every sector.

Our script, the row counter and a byte comparison on a copy with one changed byte
$ python3 mdf_peek.py k16.mdf
no problem found in 432 pages
$ python3 mdf_rows.py k16.mdf 2
object 325576198: 2155 rows
object 21575115: 830 rows
38 objects, 7201 rows in all
$ cmp -l northwind.mdf k16.mdf | wc -l
1
$ sha256sum northwind.mdf k16.mdf
bc4adbda51be2f1463c11387255e7a5a37db20e45980ce5554812c37e7f52876  northwind.mdf
f366fb905918b2cad4902b8a721567e5db2f7d23ff4434e1ec6a6e7d0e66f473  k16.mdf

The script says no problem and the row counter prints 7,201 rows, the same as for the original. The cmp command shows that one byte differs, and the hashes differ too. Only a hash against a trusted source finds this copy.

Header and boot page damage in an MDF file

A zeroed page 0, one changed first byte, one zeroed boot page and one changed version in the boot page were all flagged. That is 16 of 16 copies. The row counter printed the same totals on all 16, because it does not read page 0 or page 9.

The script on a copy with one changed first byte and on a copy with one changed version
$ python3 mdf_peek.py k2.mdf
page 0 does not start with 01 0F 00 00 (file header page)
$ file k2.mdf
k2.mdf: data

$ python3 mdf_peek.py k4.mdf
database version 999 is not one we know

The file command said data for the changed first byte, and it says data for the original too. A refusal from one tool does not show that rows are gone. The rows were all in the data pages, and they were still there.

Cut and extended MDF files

A cut at 10 percent of the pages kept 781 of the 7,201 rows of the first Northwind copy. A cut at 50 percent kept 3,650. Across all four MDF files, cuts at 10 percent lost 89 to 94 percent of the rows and cuts at 50 percent lost 49 to 59 percent.

The script on one copy cut at 10 percent, on a page edge
$ python3 mdf_peek.py k5.mdf
page 43 is in use by the PFS page but is missing
page 44 is in use by the PFS page but is missing
page 45 is in use by the PFS page but is missing
page 48 is in use by the PFS page but is missing
page 49 is in use by the PFS page but is missing
page 50 is in use by the PFS page but is missing
... and 15 more lines
$ wc -c < k5.mdf
352256

The script says the PFS page marks pages as in use that are missing. A cut inside a page also trips the size rule. 100 junk pages added at the end changed no row, and our script did not flag any of those 4 copies.

The script on a copy with 100 junk pages added at the end
$ python3 mdf_peek.py k8.mdf
no problem found in 532 pages

That is a gap. The script reads the pages that the PFS page marks as in use, so pages after the last one are not read. Compare the size and the hash with the source to catch an extended file.

Allocation pages in an MDF file

Zeroing the PFS page, the GAM page or the first IAM page was flagged on all 12 copies. The PFS page is the map that our checks trust, so zeroing it made the row counter print fewer rows. On the three small files it printed 0 rows.

The script and the row counter on a copy with the GAM page zeroed
$ python3 mdf_peek.py k10.mdf
page 2 is in use by the PFS page but is empty
$ python3 mdf_rows.py k10.mdf 2
object 325576198: 2155 rows
object 21575115: 830 rows
38 objects, 7201 rows in all

For the GAM page and the IAM page the row counter still printed the totals of the original. Our script flagged them because the PFS page says the pages are in use and they are empty. The rows were in the data pages, and those were untouched.

Full pages in an MDF file

One zeroed data page was flagged on all 16 copies, and it cost between 2 and 261 rows. Zeroing 5 percent of the data pages was flagged on 4 of 4. One data page filled with junk was flagged on 12 of 12, and it cost between 1 and 140 rows.

The script, the row counter and the file command on a copy with one data page zeroed
$ python3 mdf_peek.py k12.mdf
page 195 is in use by the PFS page but is empty
$ python3 mdf_rows.py k12.mdf 3
object 325576198: 1894 rows
object 21575115: 830 rows
object 3: 792 rows
38 objects, 6940 rows in all
$ file k12.mdf
k12.mdf: data

The row counter prints 6,940 rows and not 7,201. The file command says data, as it did for the original. The script names the page, so you know where to look. A zeroed index page was flagged on 12 of 12, and the row counter did not notice it.

The script on a copy with one data page filled with junk
$ python3 mdf_peek.py k14.mdf
page 408 says it is page 4123831670 of file 43764
page 408 fails its checksum

A few changed bytes in an MDF file

One changed byte in a data page was flagged on 4 of 16 copies. Sixteen changed bytes were flagged on 3 of 12. One changed byte in an index page was flagged on 3 of 12. Every flag came from AdventureWorks, so all 10 of them are checksum failures.

The three torn bit files gave no flag on any of the 30 copies in these three kinds. One changed byte in unused space was flagged on none of 4, and that is right, because no page in use changed. Our script cannot see one changed byte unless the MDF file has a checksum.

What our two checks catch in an MDF file

The script flagged 94 of the 132 copies. The row counter printed other totals on 48 copies, and the script flagged all 48. So the counter found nothing that the script missed, and 38 copies passed both checks.

The PFS rule matters. Without it the script would flag 46 copies, and with it the script flags 94. It found 48 copies that no other rule saw, like a zeroed data page, a cut file and a zeroed map.

What the groups show

Results by group of damaged MDF files
Group What we found
A. Header and boot page (1 to 4) 16 copies, and the script flagged all 16. The row counter printed the original totals on all 16, because the rows are in data pages.
B. Cut or extended (5 to 8) 16 copies. The script flagged the 12 cut copies, and they lost 49 to 94 percent of the rows. It flagged none of the 4 copies with junk pages added.
C. Allocation pages (9 to 11) 12 copies, and the script flagged all 12. Only the zeroed PFS page changed the row totals.
D. Full pages (12 to 15) 44 copies, and the script flagged all 44. 32 of them lost rows, between 1 and 53,012. The zeroed index pages lost none.
E. Single bytes (16 to 19) 44 copies. The script flagged 10, all from the checksum file. 21 silent copies had a changed data page.

Read the grid with care. A flag means our script named a fault, not that SQL Server would refuse the copy. We did not start SQL Server. Every test changed one thing in a file that was in good shape, and our rules come from the same four MDF files.

What Does Our Expert Say About MDF Files? A note from Neeraj Singh on trusting a database with care

Copy an MDF file before you touch it, and keep the original. Attaching changes the MDF file, and many tools read a damaged MDF file without a word. In our test 38 copies got no flag, and 21 of them had changed data pages.

Neeraj Singh

Expert insight

An MDF file is a database made of pages, and one changed byte can pass every tool that only reads it. In our test the file command said data on all 132 copies, and 38 got no flag from our script. Copy the MDF file first, hash it and attach it only on a test server you can throw away.

Neeraj Singh Manager, Tech Support & Operations 19+ years fixing Windows and system errors

Why an MDF database needs care

People think a database file is safe because they only look at it. An MDF file is a set of pages that point at one another. One changed byte can be in a data page and pass every tool that does not read the checksum.

Attaching adds a second risk, because the server upgrades the MDF file. Microsoft says the database is automatically upgraded to the version of the new instance. Attach a copy to any test server, hash the original and compare row counts.

Keep the original. Copy the MDF file before you attach it, and write down its SHA256 hash. The hash shows which file you received and whether a later copy differs. Keep the LDF log file with it.

How Do You Open an MDF File? Attach it to SQL Server, use LocalDB or read it with a viewer

SQL Server opens an MDF file by attaching it. Without a server, read one with a viewer from SysTools or Freeviewer. Copy the MDF file before you attach it, and keep the LDF log file with it.

We read MDF files with our own scripts on Linux. We did not start SQL Server, SQL Server Management Studio or the two viewers. The steps below come from Microsoft’s pages and from the pages of the two vendors, and we say so where it matters.

Attach an MDF file in SQL Server Management Studio

Microsoft’s page on attaching a database names the steps. Before you start, know that the database must be detached from any instance first. All data files must be available, and you need the CREATE DATABASE, CREATE ANY DATABASE or ALTER ANY DATABASE permission.

  1. Copy the MDF file and the LDF file to a folder that the server can read.
  2. In SQL Server Management Studio, right click Databases and select Attach.
  3. In the Attach Databases dialog box, select Add and select the .mdf file in the Locate Database Files box.
  4. If the dialog lists a log file that is missing, correct its path in the grid or remove it, as Microsoft says.
  5. Select OK, and then check the tables. Remember that the MDF file is upgraded when it attaches.

Attach an MDF file with a Transact-SQL command

Microsoft’s page on CREATE DATABASE says FOR ATTACH creates a database by attaching existing operating system files. The page on sp_attach_db says that older procedure will be removed in a future version and recommends CREATE DATABASE FOR ATTACH instead.

Syntax from Microsoft’s page. We did not start it
CREATE DATABASE northwind
ON (FILENAME = N'C:\Data\northwind.mdf')
FOR ATTACH;

Add the path of the LDF file to the command when you have one. Without a log file, Microsoft says the attach operation tries to build a new one. That works for the read write database that was shut down properly, and the causes part lists the limits.

Open an MDF file with LocalDB

Microsoft’s page on LocalDB calls it a feature of SQL Server Express for developers. It gives the connection string that names the MDF file, with Server set to (LocalDB)\MSSQLLocalDB and AttachDbFileName set to the path of the .mdf file. We did not test it.

Where MDF files live

Microsoft says data files live in a Data folder, in the MSSQL folder of the instance, under the Microsoft SQL Server folder in Program Files. On Linux, the mssql-conf page gives /var/opt/mssql/data as the default folder for new database files.

Your administrator can change the default folder, so the database properties in Management Studio show the full path of a file. A file that you find by name is only a candidate, because the ending is a recommendation.

Open an MDF file with a viewer

Two vendors list viewers for MDF files on Windows. We tested neither, and both pages come from the vendors.

SysTools MDF Viewer

Read MDF and NDF files on Windows without SQL Server

Free version previews only

Freeviewer MDF Viewer

Read MDF files on Windows without SQL Server

Free version previews only

The SysTools page lists version 13.0 and 6.72 MB. It opens MDF and NDF files without a SQL Server instance, and it names SQL Server 2000 to 2022 and Windows 7 to 11. The free version scans and previews. The page lists the Pro edition at $249 that exports to a SQL Server database, scripts or CSV.

The Freeviewer page also lists version 13.0 and 6.72 MB, a free version and the Pro edition at $249. It names SQL Server 2000 to 2025. The two pages name different version ranges for the free tool, so read the page before you download.

Other ways to read an MDF file

FileInfo’s page on .mdf files lists Microsoft SQL Server 2019 and Visual Studio 2022 for the SQL Server entry. A Microsoft forum answer says an MDF file is binary and not meant to be opened in an application. It says to attach it to a running server and read it with Transact-SQL.

If your file is the disc image from Alcohol 120%, Wikipedia says Daemon Tools, CDemu, MagicISO, PowerDVD and WinCDEmu read the format. Look for a file with the same name and the ending .mds beside it.

How our tools did on the damaged MDF files

Every tool gets its own row below. The numbers cover our 132 damaged copies, and the tools that read files without a server are the ones we used.

How every tool did on our damaged MDF files
Tool On our damaged copies
Our 64 line script Flagged 94 of the 132 copies and none of the 4 intact MDF files. It gave no flag on 38 copies, and 21 of them had changed data pages.
Our 26 line row counter Printed other totals on 48 copies, and the script flagged all 48. It printed the original totals on 21 copies with changed data pages.
file 5.45 Said data on all 132 copies and on the 4 intact MDF files.
SQL Server Not tested. Microsoft’s pages say what attaching does, and the sections above list the steps.
Viewers Not tested. The vendor pages list free previews and the Pro edition at $249.

How Do You Check an MDF File? Six steps and two short scripts

Check an MDF file in six steps. Hash it, check its size, read its first bytes and its version, count the rows and use our script to read the pages. No check proves that every row is right.

The six steps to check an MDF file

  1. Copy the MDF file, write down its SHA256 hash and work on the copy.
  2. Check the size with wc -c < mydata.mdf. It must be a multiple of 8,192 bytes, and a primary file has at least 10 pages.
  3. Read the first bytes with xxd -l 32 mydata.mdf. They should start with 01 0F 00 00. All 4 of our public MDF files do.
  4. Read the version with xxd -s 73824 -l 16 mydata.mdf. Counting from 0, bytes 4 and 5 of that line are the database version and bytes 6 and 7 the creation version, low byte first. Our sample shows 8f 02 and 1b 02, which are 655 and 539.
  5. Count the rows with the row counter below and compare the totals with your source.
  6. Use the 64 line script below. Stop if a check names a fault, if the version is too new for your server or if the MDF file came from a source you do not trust.
Commands that read our MDF file and change nothing
$ sha256sum northwind.mdf
bc4adbda51be2f1463c11387255e7a5a37db20e45980ce5554812c37e7f52876  northwind.mdf
$ file northwind.mdf
northwind.mdf: data
$ wc -c < northwind.mdf
3538944

$ xxd -l 32 northwind.mdf
00000000: 010f 0000 0801 0000 0000 0000 0000 0000  ................
00000010: 0000 0000 0000 0100 6300 0000 6a1b 9404  ........c...j...
$ xxd -s 73824 -l 16 northwind.mdf
00012060: 0000 a405 8f02 1b02 0000 0000 0000 0000  ................

The file command says data, because it has no rule for an MDF file. The hash is the line that matters. It shows which file you have, and it must match the source before you go on.

The row counter for MDF files

The Python script below does step 5. It reads the pages that the PFS page marks as in use. On every data page at level 0 it takes the number of row slots, subtracts the ghost rows and adds the result to the table number of the page. It prints the biggest tables and the total.

mdf_rows.py
#!/usr/bin/env python3
"""mdf_rows.py counts the rows of every table from the data pages of an MDF file.
Use: python3 mdf_rows.py mydata.mdf. It changes no file and starts nothing."""
import struct, sys, collections
PAGE = 8192

def rows_by_object(data):
    n = len(data) // PAGE
    out = collections.Counter()
    for start in [1] + list(range(8088, n, 8088)):
        pfs = data[start * PAGE:(start + 1) * PAGE]
        for k in range(8088):
            i = k if start == 1 else start + k
            if i >= n or not pfs[100 + k] & 0x40:
                continue
            p = data[i * PAGE:(i + 1) * PAGE]
            if p[1] == 1 and p[3] == 0:
                slots, obj, ghost = struct.unpack_from('<H', p, 22)[0], struct.unpack_from('<I', p, 24)[0], struct.unpack_from('<H', p, 58)[0]
                out[obj] += slots - ghost
    return out

if __name__ == '__main__':
    rows = rows_by_object(open(sys.argv[1], 'rb').read())
    for obj, count in rows.most_common(int(sys.argv[2]) if len(sys.argv) > 2 else 6):
        print('object %d: %d rows' % (obj, count))
    print('%d objects, %d rows in all' % (len(rows), sum(rows.values())))

It prints table numbers and not names, because the names live in system tables that it does not read. On our sample it prints 7,201 rows in 38 objects. Object 21575115 is the Orders table with 830 rows. The script changes no file and starts nothing.

The row counter on our sample MDF file
$ python3 mdf_rows.py northwind.mdf 4
object 325576198: 2155 rows
object 21575115: 830 rows
object 3: 792 rows
object 41: 705 rows
38 objects, 7201 rows in all

Compare the two lists, yours and the source’s, and the totals. A copy with one data page zeroed prints 6,940 rows, and one copy cut at 10 percent prints 781. The counter found none of the 21 silent copies, because one changed byte does not change a row count.

The 64 line script that reads MDF files

The Python script below does step 6. It checks the size, the start of page 0 and the type and version of the boot page. Then it reads the PFS page. For every page that the PFS page marks as in use it checks the page number, the file number and the checksum or the torn page bits.

It names every fault it finds, and it changes no file. It computes the checksum the way SQL Server does, with an exclusive or over the words of every 512 byte sector. It does not read pages that the PFS page marks as free, because they can contain old content.

mdf_peek.py
#!/usr/bin/env python3
"""mdf_peek.py reads the structure of an MDF file and names every fault it can see.
Use: python3 mdf_peek.py mydata.mdf. It changes no file and starts nothing."""
import struct, sys
PAGE = 8192
VERSIONS = {539: '2000', 611: '2005', 612: '2005', 655: '2008', 661: '2008 R2', 706: '2012',
            782: '2014', 852: '2016', 869: '2017', 904: '2019', 957: '2022'}

def rotl(x, n):
    return ((x << n) | (x >> (32 - n))) & 0xFFFFFFFF if n else x

def checksum(page):
    w = list(struct.unpack('<2048I', page))
    w[15] = 0
    out = 0
    for i in range(16):
        s = 0
        for v in w[i * 128:(i + 1) * 128]:
            s ^= v
        out ^= rotl(s, 15 - i)
    return out

def peek(data):
    msgs, n = [], len(data) // PAGE
    if len(data) % PAGE:
        msgs.append('size %d is not a multiple of %d' % (len(data), PAGE))
    if n < 10:
        return msgs + ['only %d pages, a primary file has at least 10' % n]
    page = lambda i: data[i * PAGE:(i + 1) * PAGE]
    if page(0)[:4] != b'\x01\x0f\x00\x00':
        msgs.append('page 0 does not start with 01 0F 00 00 (file header page)')
    if page(9)[1] != 13:
        msgs.append('page 9 has type %d, the boot page has type 13' % page(9)[1])
    elif struct.unpack_from('<H', page(9), 100)[0] not in VERSIONS:
        msgs.append('database version %d is not one we know' % struct.unpack_from('<H', page(9), 100)[0])
    for start in [1] + list(range(8088, n, 8088)):
        pfs = page(start)
        if pfs[1] != 11:
            msgs.append('page %d should be a PFS page and has type %d' % (start, pfs[1]))
            continue
        for k in range(8088):
            i = k if start == 1 else start + k
            if not pfs[100 + k] & 0x40:
                continue
            p = page(i) if i < n else b''
            if not any(p):
                msgs.append('page %d is in use by the PFS page but %s' % (i, 'is missing' if i >= n else 'is empty'))
                continue
            pid, fid = struct.unpack_from('<IH', p, 32)
            if pid != i or fid != 1:
                msgs.append('page %d says it is page %d of file %d' % (i, pid, fid))
            flag, torn = struct.unpack_from('<H', p, 4)[0], struct.unpack_from('<I', p, 60)[0]
            if flag & 0x200 and checksum(p) != torn:
                msgs.append('page %d fails its checksum' % i)
            elif not flag & 0x200 and flag & 0x100 and any((p[s * 512 + 511] & 3) != torn & 3 for s in range(1, 16)):
                msgs.append('page %d fails its torn page bits' % i)
    return msgs

if __name__ == '__main__':
    data = open(sys.argv[1], 'rb').read()
    out = peek(data)
    print('\n'.join(out[:20]) if out else 'no problem found in %d pages' % (len(data) // PAGE))
    if len(out) > 20:
        print('... and %d more' % (len(out) - 20))

On our sample it reads 432 pages and reports no problem. It read AdventureWorks, with 26,272 pages, in 2.4 seconds. It flagged none of the 4 intact MDF files. It names a fault only when the pages disagree with their own header.

The script on our sample and on two damaged copies
$ python3 mdf_peek.py northwind.mdf
no problem found in 432 pages

$ python3 mdf_peek.py k12.mdf
page 195 is in use by the PFS page but is empty

$ python3 mdf_peek.py k14.mdf
page 408 says it is page 4123831670 of file 43764
page 408 fails its checksum

The copy with a junk page shows two faults at once. The page says it is page 4123831670 of file 43764, and it also fails its protection value. The script names the page, and you copy the MDF file again from its source.

What the checks cannot see

38 copies passed our script. 21 had one changed byte in a data page, and 17 had a change in an index page, an unused page or the end of the MDF file. The three torn bit files hide one changed byte, and junk added at the end is never read.

Write down the facts of your original MDF file. Keep its size, its SHA256 hash, its two version numbers and the row total. A copy that differs in any of them is a different file, even when every tool reads it.

Our scripts never check that a name, a number or a date is right. They show whether the pages agree with themselves, and nothing more. We did not test an encrypted file, so we cannot say how the script reads one.

Want the causes of an error? Go to the causes.

Is an MDF File Safe to Open and Share? Reading starts no code, and attaching asks for trust

Reading an MDF file with a script starts no code, but attaching one to SQL Server is another matter. Microsoft says not to attach or restore databases from unknown or untrusted sources. Treat every MDF file as private data.

Microsoft’s page on sp_attach_db warns that such a database could contain malicious code. The code could execute unintended Transact-SQL or damage the schema and the physical structure. The page advises DBCC CHECKDB on a nonproduction server, plus a look at stored procedures and other code in the database.

We scanned no file for malware, and our 4 MDF files are public samples. Microsoft’s page on DBCC CHECKDB describes the check. Our scripts only read bytes, so reading with them starts nothing.

What is inside an MDF file

Tables and rows Every row of every table is in the MDF file. Our sample is small, and a large database can store names, prices and notes.
Objects and code Stored procedures, triggers and functions live in the database. Microsoft’s warning names stored procedures and other user defined code.
Names you can read Names of tables and columns are in the MDF file as UTF-16 text. The strings command reads them without SQL Server.
Old content in free pages Pages that are not in use can still contain content. Our sample has 21 of them, and AdventureWorks has 2,578.
The strings command on our MDF file
$ strings -e l northwind.mdf | head -3
Northwind
Northwind
Northwind

The log file next to an MDF file

An attach needs the data files, and Microsoft says to keep all the detached log files until the database attaches without them. The log records the changes in order, and our page on LDF files shows that it can contain old values. Look at both files before you send either.

Before you share an MDF file

  1. Attach your copy on any test server and list the tables. Look at what is there.
  2. Ask if the other side needs every table. Send fewer tables when it needs fewer.
  3. Leave the LDF file out unless the other side needs it, and read what it contains first.
  4. Send the MDF file over a channel you trust, and send its SHA256 hash by another route.
  5. Delete your extra copies when the other side confirms the MDF file.

Look before you send. A database can store more than you remember. Read the table list and a few rows of every table before you share the MDF file, and remove names and notes that the other side does not need.

Why Will Your MDF File Not Attach? Eight causes, and what to do about every one

MDF files fail to attach for eight reasons. It can be another kind of file or any newer version. A file or a right can be missing. The database can still be attached. The header, a page or the length of the MDF file can also be wrong.

The table lists what Microsoft says and what we saw in our 132 damaged copies. We read files with our own scripts and did not start SQL Server, so read every fix as a first step and not as a final answer.

Eight causes of MDF files that will not attach
Cause Details and fix
You have a different kind of file A Microsoft Q&A answer says an .mdf file can be a secondary data file or not a SQL Server file at all. Error 5171 says the MDF file is not a primary database file. With the first byte changed, our script said page 0 does not start with 01 0F 00 00, and the file command said data. Fix: Check that the size is a multiple of 8,192 and that the MDF file starts with 01 0F 00 00.
The file is from any newer version Microsoft says a database from any more recent version can’t be attached in earlier versions. Error 948 names both version numbers. Our script prints an error for a version it does not know, like the 999 we wrote into one copy. Fix: Read the version at byte 100 of page 9 and use a server that supports it.
A data file or the log is missing Microsoft says all data files must be available to attach. For a missing log file, the attach tries to build a new one for the read write database that was shut down properly. It cannot do that for a read only database. Fix: Keep every MDF, NDF and LDF file together until the attach works.
The database is still attached or in use Microsoft says the database must first be detached from any existing instance, and attaching one that is not detached returns an error. We did not test this. Fix: Detach the database or stop its use. Then copy the files.
A right is missing Attaching needs the CREATE DATABASE, CREATE ANY DATABASE or ALTER ANY DATABASE permission, says Microsoft. It also says file access permissions are set during detach and attach. We did not test this. Fix: Ask your administrator which accounts can read the folder.
The header or boot page is damaged A zeroed page 0, one changed first byte, one zeroed boot page and one changed version were all flagged, on 16 of 16 copies. The row counter still printed the original totals on every one. Fix: Compare the MDF file with its source, and let the script name the wrong byte.
The file is cut short or extended Cuts at 10 and 50 percent were flagged on all 12 copies, and they lost 49 to 94 percent of the rows. 100 junk pages at the end changed no row, and our script did not flag any of the 4 copies. Fix: Compare the size and the hash with the source.
A page is damaged A zeroed data page was flagged on 16 of 16 copies and cost 2 to 261 rows. One changed byte passed the script on 30 of 40 copies. Microsoft says error 824 is a severe condition and asks for DBCC CHECKDB. Fix: Restore from the last good backup, as Microsoft recommends.

When the script is the problem and not the MDF file

Our script gave no flag on 38 damaged copies, so a report with no flag does not prove a file is good. It also reads only pages that the PFS page marks as in use, so it cannot see a bad free page. Test with a second tool before you call an MDF file good or bad.

Fix an MDF file in seven steps

  1. Copy the MDF file and the LDF file, write down their SHA256 hashes and work on the copies.
  2. Check that the size is a multiple of 8,192 bytes and that the MDF file starts with 01 0F 00 00.
  3. Read the version at byte 100 of page 9 and compare it with the versions that your server supports.
  4. Put every data file and the log file in one folder, and detach the database if it is still attached.
  5. Read the MDF file with the row counter and the page script, and note every fault they name.
  6. If a page is damaged, restore from the last good backup. Microsoft recommends this as the primary way to recover from errors that DBCC CHECKDB reports.
  7. Treat REPAIR_ALLOW_DATA_LOSS as the last step and use it on a copy. Microsoft says its repairs can cause some data loss. We tested no repair, so none is promised here.

We did not test repairs on files from other people. An MDF file that passes our scripts can still fail to attach, and a file that our script flags can still attach. Only SQL Server knows what it accepts.

What to send when you ask for help

If a forum or a support team asks about your MDF file, send these lines. They show what the MDF file is and where the tools stopped, and they save rounds of questions. Remove names and private data first.

A message that gets an answer
Subject: MDF file will not attach
File: name, size in bytes and SHA256 hash
First bytes: the output of xxd -l 32 mydata.mdf
Version: bytes 100 to 103 of page 9
Row counter: the output of mdf_rows.py
Page script: the output of mdf_peek.py
Server: the SQL Server version and edition
Error: the number and the text
History: where the MDF file came from and what changed

Not an error, but a question about similar files? Go to the versus part.

How Do You Move or Convert an MDF File? Detach and attach, restore a backup or count the rows without a server

You cannot convert an MDF file by renaming it. To move a database, detach it, copy its files and attach them. Another route is to restore a backup. We tested no conversion, and our scripts only read bytes.

This part reports what Microsoft says and what we tested with a rename. A converter would read the MDF file and write new files, and the original file stays unchanged.

Move an MDF file to another server

Microsoft’s page on upgrading with detach and attach says the database is available immediately after the attach and is automatically upgraded. It says this prevents the database from being used with an older version. A move to any newer server cannot be undone, so keep a copy.

Size limits that can block a move

Microsoft’s page for SQL Server 2022 lists 10 GB as the maximum relational database size of the Express edition. The same row on the page for SQL Server 2019 says 10 GB. Microsoft’s list of what is new in SQL Server 2025 says 50 GB. Our biggest file is 215,220,224 bytes.

Restore a backup instead

A backup is a different file. Microsoft’s page on full backups says to use .bak as the extension to simplify file classification. The page for DBCC CHECKDB recommends a restore from the last known good backup. Our page on MDF repair lists when to prefer it.

Read the rows without a server

Our row counter totals the rows of every table from the data pages, and it prints no values. The pages of SysTools MDF Viewer and Freeviewer MDF Viewer list the Pro edition at $249 that exports. SysTools names SQL Server, scripts and CSV. We tested neither.

What you cannot convert by renaming an MDF file

Renaming an MDF file to .ndf changes only the name. We renamed our sample, and the SHA256 hash stayed the same and the file command still said data. We read no NDF file, so we cannot say how its first page differs from page 0 of an MDF file.

Our sample before and after the rename
$ sha256sum northwind.mdf northwind-renamed.ndf
bc4adbda51be2f1463c11387255e7a5a37db20e45980ce5554812c37e7f52876  northwind.mdf
bc4adbda51be2f1463c11387255e7a5a37db20e45980ce5554812c37e7f52876  northwind-renamed.ndf
$ file northwind-renamed.ndf
northwind-renamed.ndf: data
Conversions and how much we know
Task What we know
Count the rows without a server Tested. Our row counter printed 7,201 rows for the sample.
Move to any newer server Not tested. Microsoft says attaching upgrades the MDF file, and it cannot go back.
Move to an older server Does not work, says Microsoft. A database from any more recent version can’t be attached in earlier versions.
MDF to CSV with a viewer Not tested. The vendors list the Pro edition at $249.
MDF to NDF by renaming Does not work. The hash did not change.

How Does an MDF File Differ From NDF, LDF, BAK and MDB Files? One primary file, a secondary file, a log, a backup and an Access database

An MDF file is the primary data file of a SQL Server database. An NDF file is a secondary data file, an LDF file is the transaction log and a BAK file is a backup. An MDB file belongs to Microsoft Access.

People mix these types up because several of them are in the same folder or store tables. The table sorts them by the program that writes them and by what they store.

MDF files next to similar files
Type What it is
MDF The primary data file. Microsoft says every database has one, and that it points to the other files.
NDF A secondary data file. Microsoft recommends .ndf for it, and a secondary file can still have the .mdf ending, says one Microsoft Q&A answer.
LDF The transaction log. Our guide to LDF files covers it.
BAK A backup file. Microsoft recommends .bak as the ending of a full backup, and a restore reads it.
MDB An Access database in the format of Access 2003 and older. Our guide to MDB files covers it.
ACCDB The Access format since Access 2007. Our guide to ACCDB files covers it.
SQLITE A SQLite database in one file. Our guide to SQLITE files covers it.
MDS The sidecar of an Alcohol 120% disc image. PRONOM’s record for the sidecar file says it is found alongside files with the ending .mdf.

An MDF file has many tables and a SQLite file has many too. A viewer for one type does not read the other, so check the first bytes before you install a tool.

What Is the MDF File Format Made Of? The facts we could check, and where they came from

An MDF file is a SQL Server database in pages of 8,192 bytes. Microsoft documents the page types and the header, and it publishes no file format specification that we found. The facts below come from Microsoft, Paul Randal, Wikipedia and our checks of 4 files and 132 copies.

Facts about the MDF file format
Part What we checked
Name MDF is the recommended ending for the primary data file of a SQL Server database. (Microsoft)
Specification Microsoft documents the page types and the 96 byte header. We found no file format specification, and no PRONOM, Library of Congress or IANA record for the SQL Server file. (our searches)
Signature Page 0 starts with the bytes 01 0F 00 00. It is a page header and not a documented signature. All 4 of our MDF files start that way. (our MDF files)
Page size 8,192 bytes, and eight pages make an extent of 64 KiB. (Microsoft)
Page header 96 bytes. Byte 1 is the type. Bytes 22 and 23 give the row count, bytes 24 to 27 the table number and bytes 32 to 37 the page and file number. Bytes 60 to 63 give the protection value. (Paul Randal, our MDF files)
Row limit 8,060 bytes of data and overhead in one row on a page. (Microsoft)
Boot page Page 9, type 13. Bytes 100 and 101 give the version and bytes 102 and 103 give the creation version. (Paul Randal, our MDF files)
Allocation maps PFS on page 1, GAM on page 2, SGAM on page 3, differential map on page 6 and bulk change map on page 7. A PFS page comes every 8,088 pages. (Microsoft, our MDF files)
Page types 1 data, 2 index, 3 text, 8 GAM, 9 SGAM, 10 IAM, 11 PFS, 13 boot, 15 file header, 16 DIFF and 17 ML. (Microsoft, our MDF files)
Protection Torn page bits or a checksum. Microsoft says the default is CHECKSUM. Three of our MDF files use torn bits and AdventureWorks uses a checksum. (Microsoft, our MDF files)
Versions Internal numbers 539 for SQL Server 2000 up to 957 for 2022 and 998 for 2025. Microsoft lists none. (Wikipedia, our MDF files)
Express limit 10 GB for SQL Server 2019 and 2022, and 50 GB for SQL Server 2025. (Microsoft)
Default folder A Data folder under the MSSQL folder of the instance on Windows, and /var/opt/mssql/data on Linux. (Microsoft)
Our counts 4 public MDF files, 132 damaged copies, our 64 line script and a 26 line row counter.

About the values we list

Rules about pages come from Microsoft’s guide to pages and extents, Randal’s anatomy of a page article and Microsoft’s database files guide. Byte offsets come from our MDF files. Where the sources disagree or say nothing, we say so.

What we left out

We damaged 4 MDF files and every test changed one thing. A database with years of use, many files and large objects can react in other ways. We did not damage an NDF file, and we did not test an encrypted file or a file from SQL Server 2022.

We did not start SQL Server, attach a file, use DBCC CHECKDB or open the two viewers. We used our own scripts and the file command only. Other versions of the file command can print other text. We counted rows and not their values.

The public MDF files are sample databases and not business data. We left out filegroups, memory optimized files, filestream data and compression, because we had no file to read them from.

Sources checked

For the MDF file, see Microsoft’s overview of database files, the page on PAGE_VERIFY and the page on attaching. For the other meanings, see Wikipedia’s MDF disambiguation page, PRONOM’s record for the disc image and the ASAM page on its format.

For errors and limits, see Microsoft’s page on error 824 and the page on error 948. For the boot page, see Paul Randal’s article on boot pages. Every count came from files and scripts in our research folder.

Frequently Asked Questions About MDF Files

What is an MDF file?

An MDF file is the primary data file of a Microsoft SQL Server database. It stores tables, indexes and rows in pages of 8,192 bytes. Microsoft recommends the .mdf ending for it and .ldf for the log.

Is every MDF file a SQL Server file?

No. The same ending names an Alcohol 120% disc image and an ASAM measurement data file. A SQL Server file has a size that is a multiple of 8,192 bytes and starts with 01 0F 00 00. All 4 of our public MDF files do.

How do I open an MDF file?

Attach it to SQL Server in Management Studio or with CREATE DATABASE and FOR ATTACH. LocalDB can attach it from the connection string. Keep the log file with it, and copy both files first. We read MDF files with our own scripts and did not start SQL Server.

How do I open an MDF file without SQL Server?

Use a viewer from SysTools or Freeviewer on Windows. Both pages say the free version previews the data and list the Pro edition at $249. Our scripts count rows and check pages on Linux, and they print no values.

Is an MDF file safe to open?

Reading an MDF file with a script starts no code. Attaching one to SQL Server is different, because Microsoft says a database from an unknown source could contain malicious code. Check it on a nonproduction server first and attach only files you trust.

What is the difference between MDF, NDF and LDF files?

An MDF file is the primary data file, and an NDF file is a secondary data file. An LDF file is the transaction log. A database has one primary data file and at least one log file. All data files must be available to attach.

How do I check an MDF file?

Hash the MDF file, check that its size is a multiple of 8,192 bytes and read its first bytes and its version. Count the rows and use our 64 line script. Together they flagged 94 of our 132 damaged copies, and 38 copies passed.

Why will my MDF file not attach?

The file can be from any newer version, which gives error 948. It can be a secondary file, which gives error 5171. A data file or the log can be missing, or the database can still be attached. A damaged page gives error 824.

Does the file command prove that an MDF file is good?

No. It said data on all 132 of our damaged copies and on the 4 intact MDF files. It has no rule for an MDF file, so a damaged page does not change its answer. Hash the MDF file and compare it with the source.

Does an MDF file have a signature?

Its first page has a fixed start. The first four bytes are 01 0F 00 00, the header of page 0. All 4 of our public MDF files start that way. Microsoft documents it as a page header and not as a signature, and we found no registry entry.

Can I rename an MDF file?

You can change the name, but nothing inside changes. We renamed our sample to .ndf, and its SHA256 hash stayed the same. The ending is a recommendation, so SQL Server does not need the name, but a rename does not make a primary file a secondary one.

How big can an MDF file be?

Microsoft lists 10 GB as the maximum relational database size of the Express edition in SQL Server 2019 and 2022, and 50 GB in SQL Server 2025. Larger editions list far more. Our biggest public MDF file is 215,220,224 bytes.

Still Stuck With an MDF File? Two routes out, and where to look next

Your MDF file won’t attach

Check the size and the first bytes and follow the seven steps. The cause table lists what to try in order.

You do not know what it contains

Look at how an MDF file is built, and then start our page script.

Is it the log file? An LDF file is the transaction log of a database. Our page on LDF files covers it, and the versus part shows how the two differ.

Is it an Access file? An MDB file belongs to Microsoft Access. Our page on MDB files and our page on ACCDB files cover the two formats.

Is it a small database in one file? A SQLite database is one file, and a DBF file is one table. Our page on SQLITE files and our page on DBF files cover them.

Is it the disc image or measurement data? An Alcohol 120% image has an MDS file beside it, and an ASAM file comes from a measurement tool. This page does not cover their insides.

Is the data unknown? Our page on DAT files covers files with no clear type, and the file extension resource library lists many more.

Is your type missing? Send it on the submit a file type page.