When does this error actually show up?
You're running a query in SSMS or an application, and suddenly you get STATUS_RXACT_COMMIT_NECESSARY (0x80000018). This almost always happens after you've done one of these:
- A failover occurred (SQL Server AG or mirroring) while a transaction was open.
- The client lost network connection mid-transaction and reconnected.
- You ran a batch with
BEGIN TRANSACTION, then the connection dropped, and you're trying to continue on the same session.
I've seen it most often with linked server queries or when an application uses MARS (Multiple Active Result Sets) and doesn't properly handle a failed commit. The session thinks it still has a transaction that must be completed, but the transaction is in a weird state.
Root cause in plain English
SQL Server keeps track of transactions per session. When a transaction is started, it's either active or in a state where it can be committed or rolled back. The error STATUS_RXACT_COMMIT_NECESSARY literally means: "There's a transaction that must be committed before you can do anything else."
What happens is the session's transaction is marked as COMMIT NECESSARY — that's a state where the transaction is still in progress, but SQL Server can't automatically roll it back because it thinks you might still want to commit it. This usually happens after a failover where the new primary doesn't know the exact state, or when a client connection is broken and reconnected but the session wasn't properly cleaned up.
It's not a corruption issue, and it's not a disk full or permission problem. It's just a stuck transaction state. The fix is to either commit or rollback that transaction. Don't bother restarting SQL Server — that's overkill and would disrupt other users.
The fix: commit or rollback that transaction
Here's what to do. You'll need to run these commands in the same session that got the error. If you're using SSMS, that's the same query window. If it's an app, you might need to add this logic to the retry handler.
- Check if there's an open transaction
Run this in the session that threw the error:
If it returns 0, then the error is from a previous session or a connection pool issue. Skip to step 4. If it returns 1 or more, you've got an open transaction.SELECT @@TRANCOUNT AS OpenTransactions; - Roll it back if you're unsure of its state
If you don't know what the transaction was doing, just roll it back. This is the safest option:
If you get an error like "No corresponding BEGIN TRANSACTION", then the transaction is in a state that requires a commit. Try step 3.ROLLBACK TRANSACTION; - Force a commit if rollback doesn't work
Sometimes the transaction state is such that only a commit will clear it. Run:
If that also fails, try:COMMIT TRANSACTION;
In some edge cases, you might need to runCOMMIT;SET XACT_ABORT ONbefore the commit to allow SQL Server to process it. I've seen this work on SQL Server 2016 and later. - If the session is unusable, kill it
If you can't get the transaction to commit or rollback, just kill the session. Find the session ID (SPID) from the error message or fromsys.dm_exec_sessions, then run:
That will force-close the session and roll back any pending transactions. The next new connection will be clean.KILL <spid>;
For application developers
If this happens in an app, the fix is to always wrap your transactions in a try-catch and in the catch block, call ROLLBACK. Also, check if the connection is still valid before reusing it. A simple pattern:
using (var conn = new SqlConnection(connString))
{
conn.Open();
using (var tx = conn.BeginTransaction())
{
try
{
// your commands
tx.Commit();
}
catch
{
tx.Rollback();
throw;
}
}
}But also handle the case where the error occurs after the connection has been dropped. That's when you'll see this 0x80000018. So add a retry logic that opens a fresh connection if you get this specific error.
What if it still fails?
If you've committed or rolled back and still see the error, then you're dealing with a different issue. Here's what to check:
- Connection pooling — The session might be reused from a pool with a poisoned state. Clear the pool with
DBCC FREEPROCCACHE? No, that's not it. Usesp_reset_connectionisn't manual. Just restart the application's connection pool or setPooling=falsein the connection string temporarily to test. - MSDTC issues — If you're using distributed transactions, check that the MSDTC service is running and configured correctly. In Windows, run
dcomcnfg, go to Component Services → Computers → My Computer → Distributed Transaction Coordinator. Make sure it's started. - SQL Server version specifics — I've seen this more on SQL Server 2012 and 2014 with AlwaysOn Availability Groups. If you're on those versions, apply the latest service packs. Microsoft fixed a bunch of transaction state bugs in SP3 for 2014.
- Use a new session — Sometimes the session is just unrecoverable. Open a new query window or reconnect from the app. That clears the session state immediately.
In my experience, this error is annoying but rarely requires a reboot. The transaction state gets stuck, and you just need to clear it. The steps above will fix it 99% of the time. If you're still stuck after that, check the SQL Server error log for any related messages around the time of the error. And don't forget to look for any triggers or weird session settings that might be interfering.
One last tip: if you're using linked servers, always set REMOTE PROC TRANSACTION PROMOTION to false unless you really need distributed transactions. That reduces the chance of hitting this mess.