0X8004D000

XACT_E_ALREADYOTHERSINGLEPHASE: Only One RM Per Transaction

Database Errors Intermediate 👁 1 views 📅 May 28, 2026

You're hitting XACT_E_ALREADYOTHERSINGLEPHASE because a transaction already has a single-phase resource manager enlisted, and you're trying to add another one.

Quick answer

You can only have one single-phase resource manager per transaction. Remove the duplicate enlistment or switch one RM to two-phase commit.

What's actually happening

This error shows up in COM+ applications, SQL Server linked server queries, or custom transactional code when you try to enlist a second single-phase resource manager into the same transaction. Think of it like this: the transaction coordinator (MSDTC) can handle multiple participants, but only one of them gets to be the “single-phase” guy — the one that promises to commit or abort on its own without a two-phase handshake. Once that slot is taken, any other single-phase RM gets slapped with 0x8004D000.

The typical real-world trigger: you write a .NET TransactionScope that touches two different SQL Server instances, both configured for single-phase enlistment, or you mix a SQL Server connection with a durable queue (like MSMQ) in the same transaction. MSDTC sees the first RM enlist and marks it single-phase. The second one tries the same and hits the wall.

Fix steps

  1. Identify which RMs are enlisting. Use the Windows SDK's DtcPing.exe (from Windows SDK or WDK) or enable MSDTC tracing via regedit: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSDTC\Trace\TraceLevel = 4. Check the trace logs for “EnlistSinglePhase” calls. You'll see the first RM and the second that fails.
  2. Remove the duplicate enlistment. If you control the code, refactor so only one RM uses single-phase. For TransactionScope, this often means not mixing two SqlConnection objects to different servers in the same scope. Instead, batch your work into a single connection or use a stored procedure that spans both databases on one server.
  3. Force two-phase commit on one RM. If you can't remove the second RM, make it use two-phase commit. In SQL Server, set enlist=false in the connection string and manually call EnlistTransaction with a Transaction object that doesn't specify single-phase. For custom C# code, implement IPromotableSinglePhaseNotification — but that's advanced territory.
  4. Check MSDTC configuration. On both machines, run dcomcnfg.exe → Component Services → Computers → My Computer → Distributed Transaction Coordinator. Ensure “Network DTC Access” is enabled, and “Allow Remote Clients” is checked. If one machine runs Windows Server Core, you might need Set-DtcClusterDefault -AuthenticationLevel 1 via PowerShell.
  5. Test with a minimal repro. Write a console app that enlists one RM first, then try to add a second. If the error disappears with one RM, you've confirmed the cause.

If the main fixes don't work

  • Switch to a non-transactional approach. Can you use System.Transactions.TransactionScope(TransactionScopeOption.Suppress) for part of the work? That offloads the second RM out of the transaction entirely. You lose atomicity across that boundary, but you avoid the error.
  • Use a compensating transaction pattern. Instead of enlisting two RMs, manually track state and roll back in a catch block. It's more code but eliminates the conflict.
  • Upgrade MSDTC to use Kernel Transaction Manager. On Windows 10/Server 2016+, KTM can handle multiple RMs differently, but it's not a silver bullet — still limited in practice.

Prevention tip

Design your transactions so that only one resource manager ever needs single-phase enlistment. If you need multiple durable participants (e.g., two distinct databases), force the less critical one to use PromotableSinglePhaseEnlistment or switch to two-phase. Also, never nest TransactionScope blocks that open connections to different databases — that's the #1 cause of this error in production systems I've debugged.

Was this solution helpful?