oeltayeb.com · Exchange Server Troubleshooting Toolkit

Checklist

Stalled mailbox move checklist

Based on the article: StalledDueToTarget_MdbReplication and failed moves: fixing stuck Exchange mailbox moves · 5 min read

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.

Symptoms to confirm

  • Start with an overview of every request:
powershell
Get-MoveRequest -ResultSize Unlimited | Get-MoveRequestStatistics |
  Sort-Object StatusDetail | Format-Table DisplayName, StatusDetail, PercentComplete, TotalMailboxSize -AutoSize
  • Stalled requests show one of these values in StatusDetail:
StalledDueToTarget_MdbReplication
StalledDueToTarget_MdbAvailability
StalledDueToTarget_DiskLatency
  • The 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.

Likely causes

  • 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-MoveRequestStatistics notes that many messages are temporary and that a request whose status is Queued or InProgress is 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 CopyingMessages and 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 LargeItemLimit in the same way.
  • Locks and service problems. A mailbox left locked by an earlier move, or an MRS instance that has stopped processing.

Checklist

  1. 1

    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
  2. 2

    Count the moves per target database

    powershell
    Get-MoveRequest -MoveStatus InProgress | Get-MoveRequestStatistics |
      Group-Object TargetDatabase | Format-Table Name, Count -AutoSize

    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 the New-SettingOverride commands in Microsoft's article (see References), and only if the servers have CPU, disk and network headroom.

  3. 3

    Fix replication on the target (MdbReplication)

    powershell
    Get-MailboxDatabaseCopyStatus DB02\* | Format-Table Name, Status, CopyQueueLength, ReplayQueueLength, ContentIndexState -AutoSize
    Test-ReplicationHealth -Identity EX02

    Good looks like every copy Healthy, queues near zero and every test Passed. Resume or reseed broken copies first; moves generate transaction logs quickly, so the replication network has to keep up.

  4. 4

    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.

  5. 5

    Handle bad items, then resume a failed move

    powershell
    $s.Report.BadItems | Select-Object -First 20
    Set-MoveRequest -Identity alex@contoso.com -BadItemLimit 20
    Resume-MoveRequest -Identity alex@contoso.com

    Values of 51 or more also need -AcceptLargeDataLoss; use -LargeItemLimit the same way for oversized items. Every skipped item is lost for good, so keep the limit as low as works.

  6. 6

    Locked mailboxes and MRS itself

    Check the service on the server named in MRSServerName with Test-MRSHealth -Identity EX02. Restarting MSExchangeMailboxReplication there interrupts the moves it is processing, which then resume.

  7. 7

    Last resort: start again

    Remove-MoveRequest -Identity alex@contoso.com discards the partial copy. The source mailbox stays in place until a move completes, so you can safely create a new request afterwards.

Verify

  • Good 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:
powershell
Get-MoveRequest -ResultSize Unlimited | Get-MoveRequestStatistics |
  Format-Table DisplayName, Status, StatusDetail, PercentComplete -AutoSize
Get-Mailbox alex@contoso.com | Format-List Database
powershell
Get-MoveRequest -MoveStatus Completed | Remove-MoveRequest -Confirm:$false

Prevent 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 -SuspendWhenReadyToComplete on New-MoveRequest to 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 BadItemLimit as a data-loss decision, never as a large default you set on every request.

Microsoft Learn references