You start moving mailboxes between databases and, hours later, most of them still sit at a low percentage with a StalledDueToTarget_* status, or a few have flipped to Failed. In this post I'll show how to read StatusDetail and the Mailbox Replication service (MRS) report, how to tell normal workload-management throttling from a real problem, and how to fix and resume stalled or failed moves on Exchange Server SE and Exchange 2019.
Errors this guide fixes
StalledDueToTarget_MdbReplicationGet-MoveRequestStatistics StatusDetailStalledDueToTarget_MdbAvailabilityGet-MoveRequestStatistics StatusDetailStalledDueToTarget_DiskLatencyGet-MoveRequestStatistics StatusDetailRelinquishing job because of large delays due to unfavorable server health or budget limitationsMove request report (-IncludeReport)TooManyBadItemsPermanentExceptionGet-MoveRequestStatistics FailureTypeThis mailbox exceeded the maximum number of corrupted items that were specified for this move request.Move request Message / EACCompletedWithWarningGet-MoveRequestStatistics StatusDetail
Note: This post covers moves inside your on-premises organization (New-MoveRequest or local move batches in the Exchange admin center). For moves to Exchange Online, see Hybrid mailbox migration batches: reading statuses and fixing common errors.
Symptoms#
Start with an overview of every request:
Get-MoveRequest -ResultSize Unlimited | Get-MoveRequestStatistics |
Sort-Object StatusDetail | Format-Table DisplayName, StatusDetail, PercentComplete, TotalMailboxSize -AutoSizeStalled requests show one of these values in StatusDetail:
StalledDueToTarget_MdbReplication
StalledDueToTarget_MdbAvailability
StalledDueToTarget_DiskLatencyThe MRS report of a stalled request (-IncludeReport) contains lines such as:
Relinquishing job because of large delays due to unfavorable server health or budget limitations with a request throttling state 'StalledDueToTarget_MdbAvailability'.A failed request shows Status as Failed, FailureType as TooManyBadItemsPermanentException and a message like this:
Error: This mailbox exceeded the maximum number of corrupted items that were specified for this move request.Why it happens#
- Workload management protects the servers. Before MRS writes more data, workload management (WLM) checks resources on the source and target: replication to the passive DAG copies (MdbReplication), database availability (MdbAvailability), disk latency and content-index freshness. When one of them is unhealthy the move pauses; if the delay drags on, MRS "relinquishes" the job and picks it up again later. A stall is not a failure. Microsoft's reference for
Get-MoveRequestStatisticsnotes that many messages are temporary and that a request whose status isQueuedorInProgressis still progressing normally. - Concurrency limits by design. Microsoft documents that WLM in Exchange Server 2019 allows 10 simultaneous moves from the same source or to the same target by default. In a batch of 50 mailboxes going to one database, about 10 show
CopyingMessagesand the rest show stalled states until a slot frees up. - A genuinely unhealthy target. If only a handful of moves run and they stay stalled, look for a passive copy with a growing queue, a failed or suspended copy, a database that keeps failing over, or slow storage.
- Data problems. A new move request allows zero bad items by default, so a single corrupted item can fail it. Items larger than the target allows count against
LargeItemLimitin the same way. - Locks and service problems. A mailbox left locked by an earlier move, or an MRS instance that has stopped processing.
How to fix it#
- Read the request in detail. The statistics and the last report lines tell you what MRS is waiting for.
PowerShell
$s = Get-MoveRequestStatistics -Identity alex@contoso.com -IncludeReport $s | Format-List Status, StatusDetail, PercentComplete, SourceDatabase, TargetDatabase, BadItemsEncountered, FailureType, Message $s.Report.Entries | Select-Object -Last 30 $s | Export-Clixml C:\Temp\alex-move.xml # keep a copy for later analysis - Count the moves per target database.
If ten or more are heading for one database, the stalls are throttling. Wait, spread the batch across more target databases, or raise the WLM limits with thePowerShell
Get-MoveRequest -MoveStatus InProgress | Get-MoveRequestStatistics | Group-Object TargetDatabase | Format-Table Name, Count -AutoSizeNew-SettingOverridecommands in Microsoft's article (see References), and only if the servers have CPU, disk and network headroom. - Fix replication on the target (MdbReplication).
Good looks like every copyPowerShell
Get-MailboxDatabaseCopyStatus DB02\* | Format-Table Name, Status, CopyQueueLength, ReplayQueueLength, ContentIndexState -AutoSize Test-ReplicationHealth -Identity EX02Healthy, queues near zero and every testPassed. Resume or reseed broken copies first; moves generate transaction logs quickly, so the replication network has to keep up. - Check availability and storage (MdbAvailability, DiskLatency). Confirm the target is mounted and not bouncing between DAG members with
Get-MailboxDatabase DB02 -Status | Format-List Name, Mounted, MountedOnServer, then check latency on the database and log volumes. Keep moves out of backup windows and other heavy I/O jobs. - Handle bad items, then resume a failed move.
Values of 51 or more also needPowerShell
$s.Report.BadItems | Select-Object -First 20 Set-MoveRequest -Identity alex@contoso.com -BadItemLimit 20 Resume-MoveRequest -Identity alex@contoso.com-AcceptLargeDataLoss; use-LargeItemLimitthe same way for oversized items. Every skipped item is lost for good, so keep the limit as low as works. If the mailbox shows other corruption symptoms, run New-MailboxRepairRequest against it before retrying. - Locked mailboxes and MRS itself. Check the service on the server named in
MRSServerNamewithTest-MRSHealth -Identity EX02. RestartingMSExchangeMailboxReplicationthere interrupts the moves it is processing, which then resume. If a mailbox stays locked as the target of an earlier move, the repair cmdlet has a dedicated type that is valid only while the mailbox is locked:New-MailboxRepairRequest -Mailbox alex@contoso.com -CorruptionType LockedMoveTarget. - Last resort: start again.
Remove-MoveRequest -Identity alex@contoso.comdiscards the partial copy. The source mailbox stays in place until a move completes, so you can safely create a new request afterwards.
Verify the fix#
Get-MoveRequest -ResultSize Unlimited | Get-MoveRequestStatistics |
Format-Table DisplayName, Status, StatusDetail, PercentComplete -AutoSize
Get-Mailbox alex@contoso.com | Format-List DatabaseGood looks like StatusDetail moving through CopyingMessages to Completed, and the mailbox's Database showing the target. CompletedWithWarning means something was skipped or not cleaned up, so read the report before you accept it. Then clear finished requests, because a mailbox that still has a request attached can't be moved again:
Get-MoveRequest -MoveStatus Completed | Remove-MoveRequest -Confirm:$falsePrevent it next time#
- Check DAG health (copy status, queues, content index) before every large batch, and keep watching it while the batch runs.
- Spread big batches across several target databases, run them outside business hours, and use
-SuspendWhenReadyToCompleteonNew-MoveRequestto control the final switch. - Size log volumes and backups for the transaction logs that moves generate on the target.
- Moved mailboxes stay soft-deleted in the source database for the retention period; see Reclaiming Exchange database white space for what that means for disk space.
- Treat
BadItemLimitas a data-loss decision, never as a large default you set on every request.

