0X0004D007

XACT_S_ALLNORETAIN (0x0004D007) — Transaction Aborted Cleanly

Database Errors Intermediate 👁 0 views 📅 May 27, 2026

You see this in MSDTC logs when a distributed transaction is aborted without retaining durable resources. The fix is straightforward — here's what to check.

You're staring at MSDTC logs or a transaction coordinator trace, and the error code 0x0004D007 keeps appearing. It's frustrating because the message says "transaction successfully aborted," but something's still wrong — your app hung, a stored procedure timed out, or a COM+ component failed midway. Let's cut through the noise.

The Fix

The root cause is almost always a resource manager (like SQL Server or a transactional file system) that doesn't set the retain flag when the transaction aborts. The MSDTC propagates the abort, but the RM says, "I'm done, nothing to hold onto." The error itself is informational — it's not the problem, it's the symptom.

Here's what to check in order of likelihood:

  1. Check your MSDTC security configuration. On the machine running the transaction coordinator, open dcomcnfg → Component Services → My Computer → Distributed Transaction Coordinator → Local DTC → Properties → Security. Ensure "Network DTC Access" is enabled, and check "Allow Remote Clients" and "Allow Inbound/Outbound" as needed. If you're on Windows Server 2016 or later, also tick "Enable XA Transactions" if you're using XA-compliant resources. Reboot the MSDTC service after changes.
  2. Review the transaction timeout. The default MSDTC timeout is 60 seconds. If your operation takes longer — say a bulk insert or a long-running stored procedure — the coordinator aborts the transaction, and this error appears. Set a higher timeout via registry: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSDTC\Timeout — DWORD value in seconds, up to 3600. Or configure it in your application code: TransactionManager.DefaultTimeout = TimeSpan.FromMinutes(10) in .NET.
  3. Inspect the resource manager. SQL Server is the most common culprit. Run DBCC OPENTRAN to see if there's an orphaned transaction. Also check sys.dm_tran_active_transactions for any transactions with dtc_state > 0. If you find one, kill it with KILL session_id. For Oracle, check V$TRANSACTION for pending distributed transactions.

90% of the time, step 1 or 2 resolves it. But you'll still see the error in logs because it's a normal event. The real fix is ensuring your app handles the abort gracefully — catch TransactionAbortedException and retry or log.

Why This Error Occurs

What's actually happening here is a mismatch between how the transaction coordinator and the resource manager communicate. MSDTC uses the OLE Transactions protocol, which defines two abort modes: ABORT_WITH_RETAIN and ABORT_NO_RETAIN. The XACT_S_ALLNORETAIN status means "all resource managers voted to not retain their state after the abort."

The retain flag matters because some RMs (like a transactional file system) need to hold locks after an abort to prevent inconsistency — think of a file that was partially written. But a database like SQL Server typically releases locks on abort. So when all RMs return NO_RETAIN, the coordinator logs this as a success, but your code might not expect the transaction to end.

The reason step 3 works is that orphaned distributed transactions sometimes linger with a PREPARED state. When the coordinator tries to commit after a timeout, it forces an abort, and the RM responds with no retain. Killing the orphan forces a clean state.

Less Common Variations

These are rarer but worth knowing:

  • COM+ component with TransactionRequired attribute. If a COM+ method runs outside a transaction context, it may throw XACT_E_ABORTED internally, and you'll see this error in the Application event log. The fix is to ensure the caller starts a transaction before invoking the component.
  • Linked server queries in SQL Server. A distributed query across linked servers (e.g., SQL to Oracle) can trigger this if the remote server's MSDTC is misconfigured. Run SELECT * FROM OPENQUERY(LinkedServerName, 'select 1') to test connectivity. If it hangs, you've found the culprit.
  • WCF services with TransactionFlow enabled. If a service operation expects a flowing transaction but the client doesn't include it, the service will abort with this code. Enable transaction flow in both client and server bindings (e.g., wsHttpBinding with transactionFlow="true").
  • Third-party XA drivers. Oracle's ODP.NET or IBM's DB2 drivers sometimes have a bug where they don't set the retain flag correctly during recovery. Updating to the latest driver version fixes it. Check V$XARESOURCE for stalled XA transactions.

Prevention

You can't prevent this error entirely — it's a normal part of distributed transaction lifecycle logging. But you can stop it from causing you headaches:

  1. Set explicit transaction timeouts in your application code. Don't rely on defaults. Use TransactionScope with a TimeSpan parameter in .NET, or BEGIN DISTRIBUTED TRANSACTION with LOCK TIMEOUT in SQL Server.
  2. Monitor MSDTC logs with a tool like dtcping or PerfMon counter "MSDTC Transactions/Aborted". A sudden spike means something upstream is failing.
  3. Design for idempotency — your operations should be safe to retry. If a transaction aborts, the next attempt should not corrupt data. Use savepoints or check preconditions before the real work.
  4. Avoid mixing TransactionScope with ADO.NET connections that have Enlist=false. This confuses the coordinator. Always let the ambient transaction manage enlistment.

One last thing: if you're using System.Transactions in .NET and you see this error repeatedly, check your TransactionManager.DefaultTimeout setting. I've seen teams set it to 10 minutes but forget to adjust the MSDTC registry timeout — the coordinator wins the race and aborts first. Sync both values.

Was this solution helpful?