Exchange ServerDeep dive

Reclaiming Exchange database white space: new database vs offline defrag (eseutil /d)

Why Exchange databases never shrink, how to read AvailableNewMailboxSpace, and why moving mailboxes to a new database beats eseutil /d offline defragmentation.

You archived or moved hundreds of gigabytes out of a mailbox database, yet the .edb file is exactly the same size. That's by design. In this post I'll explain how white space works in Exchange Server SE and Exchange 2019, how to measure it with AvailableNewMailboxSpace, and the two ways to give disk space back: a new database with online mailbox moves (the right default) and offline defragmentation with eseutil /d (a last resort).

How this guide is organised: How it works → Step-by-step → Verify → Tips & gotchasFlow diagram of the article's sections in reading order: 1. How it works. 2. Step-by-step (4 steps: Decide whether you need to; Purge soft-deleted mailboxes you no longer need; Recommended: move everything to a new database; Last resort: offline defragmentation). 3. Verify. 4. Tips & gotchas. Toolbox: Get-MoveRequest, Remove-MailboxDatabaseCopy, Remove-MailboxDatabase, AvailableNewMailboxSpace, MailboxRetention.1How it works2Step-by-step3Verify4Tips & gotchas1Decide whether you needto2Purge soft-deletedmailboxes you no longer…3Recommended: moveeverything to a new dat…4Last resort: offlinedefragmentationTOOLBOXGet-MoveRequestRemove-MailboxDatabaseCopyRemove-MailboxDatabaseAvailableNewMailboxSpaceMailboxRetentionHow this guide is organised: How it works → Step-by-step → Verify → Tips & gotchasFlow diagram of the article's sections in reading order: 1. How it works. 2. Step-by-step (4 steps: Decide whether you need to; Purge soft-deleted mailboxes you no longer need; Recommended: move everything to a new database; Last resort: offline defragmentation). 3. Verify. 4. Tips & gotchas. Toolbox: Get-MoveRequest, Remove-MailboxDatabaseCopy, Remove-MailboxDatabase, AvailableNewMailboxSpace, MailboxRetention.1How it works2Step-by-step1Decide whether you need to2Purge soft-deleted mailboxes you no longerneed3Recommended: move everything to a newdatabase4Last resort: offline defragmentation3Verify4Tips & gotchasTOOLBOXGet-MoveRequestRemove-MailboxDatabaseCopyRemove-MailboxDatabaseAvailableNewMailboxSpaceMailboxRetention
At a glance: how this guide is organised · 4 steps · 5 key settings and tools

How it works#

A mailbox database is an Extensible Storage Engine (ESE) file made of pages. When items, folders or whole mailboxes go away, their pages are freed inside the file, not handed back to the volume. Background database maintenance makes those pages available for reuse, so the database fills its own white space before it grows again, but the file never shrinks while mounted. Every DAG copy and every full backup carries the same white space. The usual sources:

  • Mailbox moves out. A moved mailbox isn't removed from the source straight away; it stays as a soft-deleted mailbox until the database's MailboxRetention period (30 days by default) ends.
  • Disabled or removed mailboxes, which are kept for the same retention period.
  • Purges: Recoverable Items cleanup after deleted item retention, retention policies and archiving projects.

Measuring it#

PowerShell
Get-MailboxDatabase -Status | Sort-Object Name | Select-Object Name,
  @{n='SizeGB';e={[math]::Round($_.DatabaseSize.ToBytes()/1GB,1)}},
  @{n='WhiteSpaceGB';e={[math]::Round($_.AvailableNewMailboxSpace.ToBytes()/1GB,1)}}

The -Status switch is required; without it both values are empty. Treat AvailableNewMailboxSpace as an indicator rather than an exact figure: it reports free space the database can hand to new or growing mailboxes and doesn't necessarily count every free page. Cross-check it against what the mailboxes actually hold:

PowerShell
Get-MailboxStatistics -Database DB01 |
  Group-Object { if ($null -ne $_.DisconnectReason) { "$($_.DisconnectReason)" } else { 'Connected' } } |
  Select-Object Name, Count, @{n='GB';e={[math]::Round((($_.Group | ForEach-Object {
    $_.TotalItemSize.Value.ToBytes() + $_.TotalDeletedItemSize.Value.ToBytes() }) | Measure-Object -Sum).Sum/1GB,1)}}

You get one line each for connected, soft-deleted and disabled mailboxes, including Recoverable Items. If the file is far larger than the total, the gap is white space plus internal overhead; a big soft-deleted line after a migration explains much of it. Run both scripts in the Exchange Management Shell on an Exchange server, because in a plain remote session the sizes come back as text.

Step-by-step: reclaiming the space#

1. Decide whether you need to#

White space costs disk on every copy and lengthens backups and reseeds, but it isn't a performance problem in itself. If the database will grow back into it within months, leave it. Reclaim it when you genuinely need the disk, such as after moving many mailboxes to Exchange Online.

2. Purge soft-deleted mailboxes you no longer need#

PowerShell
Get-MailboxStatistics -Database DB01 | Where-Object DisconnectReason -eq 'SoftDeleted' |
  Format-Table DisplayName, MailboxGuid, TotalItemSize -AutoSize
Remove-StoreMailbox -Database DB01 -Identity <MailboxGuid> -MailboxState SoftDeleted

Only remove entries for moves you've confirmed as complete; this is permanent. It doesn't shrink the file either, but it turns those pages into reusable white space.

Moves are online: users keep working and each mailbox only reconnects at the end of its own move. Create the new database and, in a DAG, its copies:

PowerShell
New-MailboxDatabase -Name DB01B -Server EX01 -EdbFilePath "E:\DB01B\DB01B.edb" -LogFolderPath "F:\DB01B\Logs"
Mount-Database DB01B
Add-MailboxDatabaseCopy -Identity DB01B -MailboxServer EX02 -ActivationPreference 2

Exchange warns that the Microsoft Exchange Information Store service should be restarted after a database is added; schedule that restart once the server's active databases are moved elsewhere. Then move user, system and archive mailboxes:

PowerShell
Get-Mailbox -Database DB01 -ResultSize Unlimited | New-MoveRequest -TargetDatabase DB01B -BatchName DB01-rebuild
Get-Mailbox -Database DB01 -Arbitration | New-MoveRequest -TargetDatabase DB01B -BatchName DB01-rebuild
Get-Mailbox -Database DB01 -AuditLog | New-MoveRequest -TargetDatabase DB01B -BatchName DB01-rebuild
Get-Mailbox -Database DB01 -PublicFolder | New-MoveRequest -TargetDatabase DB01B -BatchName DB01-rebuild

# Archives stored in DB01 whose primary mailbox lives in another database
Get-Mailbox -Archive -ResultSize Unlimited |
  Where-Object { "$($_.ArchiveDatabase)" -eq 'DB01' -and "$($_.Database)" -ne 'DB01' } |
  New-MoveRequest -ArchiveOnly -ArchiveTargetDatabase DB01B -BatchName DB01-rebuild

Track progress with Get-MoveRequest -BatchName DB01-rebuild | Get-MoveRequestStatistics. Moves write a comparable volume of transaction logs on the target, and workload management throttles them to protect DAG replication; if they crawl, see stalled and failed mailbox moves.

When everything has finished, remove the completed move requests, the old database's passive copies (Remove-MailboxDatabaseCopy DB01\EX02) and then the database (Remove-MailboxDatabase DB01). Exchange refuses while any mailbox remains, and it leaves the files on disk, so delete the old .edb and log folder yourself once you're sure.

4. Last resort: offline defragmentation#

Use eseutil /d only when a second database isn't an option (say, a standalone server with no room for another volume) and a long outage is acceptable:

  1. Take a full backup and confirm it can be restored.
  2. In a DAG, remove the passive copies first. Microsoft lists an offline defragmentation of any copy among the situations that require reseeding.
  3. Run Dismount-Database DB01, then check that eseutil /mh "E:\DB01\DB01.edb" reports State: Clean Shutdown.
  4. Defragment. By default the temporary database is created in the current folder, so point it at a volume with room for the compacted database plus roughly 10% (the long-standing "110%" rule of thumb):
    Command Prompt
    eseutil /d "E:\DB01\DB01.edb" /t"G:\Defrag\TEMPDFRG.EDB"
  5. Mount the database and take a new full backup straight away. Eseutil itself recommends this, because restoring an older backup rolls the database back to that point. Then re-add the DAG copies so they seed from scratch.
AspectNew database and moveseseutil /d
User impactOnline; a brief reconnect per mailboxDatabase offline for the whole run
Disk neededA volume for the new database and its logsAbout the compacted size plus 10%
DAG copiesNew copies seed normallyEvery other copy must be reseeded
ControlPer mailbox: pause, retry or remove a requestAll or nothing
Side benefitsA fresh database; corrupted items surface per mailboxNone beyond the smaller file

Verify#

PowerShell
Get-MailboxDatabase DB01B -Status | Format-List Name, DatabaseSize, AvailableNewMailboxSpace
Get-Item "E:\DB01B\DB01B.edb" | Select-Object Name, @{n='GB';e={[math]::Round($_.Length/1GB,1)}}
Get-Volume -DriveLetter E | Format-Table DriveLetter, SizeRemaining, Size -AutoSize

Good looks like a database close to the mailbox total you measured earlier, a small AvailableNewMailboxSpace, more free space on the volume and, in a DAG, every copy reporting Healthy.

Tips & gotchas#

  • Don't schedule offline defrags as routine maintenance. Background maintenance already looks after the database; nothing justifies a regular outage, reseed and fresh backup.
  • Watch the log volume during moves. If backups aren't truncating logs, the target's log disk fills long before the moves finish.
  • Set activation preferences on the new database's copies before production load lands on it; see activation preference and rebalancing.

References#

Written and checked against current Microsoft Learn documentation. Test changes with a pilot group before rolling them out to everyone, and if an admin center path has moved since, search for the setting name instead.

Spotted a mistake, or did this fix work differently for you? Email me or message me on LinkedIn — corrections are credited in the article.

Written by

Omer Eltayeb

Intune Subject Matter Expert in Cairo, Egypt, former Microsoft Cloud Solutions Architect, Microsoft Certified Trainer and Microsoft Innovative Educator Expert (2024–26) and Microsoft Elevate Educator Expert (2026–27). I share practical, step-by-step guides, study plans, scripts and toolkits for Microsoft Intune, Configuration Manager, Microsoft Entra ID, Microsoft Defender, Exchange and Microsoft 365 with the community.

Microsoft Certified Trainer (MCT) 2026Microsoft Innovative Educator Expert 2025–2026Microsoft Elevate Educator Expert 2026–2027ISC2 Certified Information Systems Security Professional (CISSP)Microsoft 365 Certified: Enterprise Administrator Expert (MS-102)