Home SQL Server Errors 1205
Microsoft SQL Server

SQL Server Error 1205

Transaction was deadlocked and chosen as the deadlock victim

Severity 13 Concurrency & Locking
Applies to: SQL Server 2005 to 2022, Azure SQL Database, Azure SQL Managed Instance
The full message
Msg 1205, Level 13, State 51, Line 1
Transaction (Process ID 58) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

Why it happens

Error 1205 means two or more transactions became stuck in a circular wait: transaction A holds a lock that transaction B wants, while transaction B holds a lock that transaction A wants. Neither can move forward, so they would wait forever. SQL Server detects this cycle and steps in to resolve it. See transactions, locks and deadlocks for the full picture.

To break the cycle the engine picks one transaction as the deadlock victim, rolls it back, and releases its locks so the other transaction can finish. It usually chooses the transaction that is cheapest to undo (the one with the least log work), unless you have set a DEADLOCK_PRIORITY. The victim receives error 1205. The message even tells you what to do next: Rerun the transaction.

This is normal behaviour under concurrency, not corruption and not a server fault. Severity 13 marks it as a transaction state error you are expected to catch and handle. Deadlocks typically appear when different sessions touch the same rows or tables in a different order, when transactions stay open too long, or when statements scan and lock more rows than they need.

Examples

Two sessions updating two rows in opposite order

-- SESSION 1
BEGIN TRAN;
UPDATE dbo.Accounts SET balance = balance - 100 WHERE id = 1;
-- (now session 2 runs its first UPDATE)
UPDATE dbo.Accounts SET balance = balance + 100 WHERE id = 2;  -- waits for session 2
COMMIT;

-- SESSION 2 (runs concurrently)
BEGIN TRAN;
UPDATE dbo.Accounts SET balance = balance - 100 WHERE id = 2;
-- (now session 1 tries its second UPDATE)
UPDATE dbo.Accounts SET balance = balance + 100 WHERE id = 1;  -- waits for session 1
COMMIT;
Result
Msg 1205, Level 13, State 51, Line 1
Transaction (Process ID 58) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

The cycle that forms

-- Session 1 holds a lock on row id = 1 and wants row id = 2.
-- Session 2 holds a lock on row id = 2 and wants row id = 1.
-- Each waits on the other: a circular wait that never resolves.
-- SQL Server kills the cheaper transaction and raises 1205 on it.
Result
Msg 1205, Level 13, State 51, Line 1
Transaction (Process ID 58) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction.

How to fix it

Retry the transaction when you catch error 1205

A deadlock victim can almost always succeed on a second attempt because the other transaction has finished. Catch error 1205 in a TRY/CATCH block (or in the client) and rerun the whole transaction a few times with a short backoff.

DECLARE @attempt INT = 0;
WHILE @attempt < 3
BEGIN
    BEGIN TRY
        BEGIN TRAN;
        UPDATE dbo.Accounts SET balance = balance - 100 WHERE id = 1;
        UPDATE dbo.Accounts SET balance = balance + 100 WHERE id = 2;
        COMMIT;
        BREAK;  -- success, leave the loop
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0 ROLLBACK;
        IF ERROR_NUMBER() = 1205 AND @attempt < 2
        BEGIN
            SET @attempt = @attempt + 1;
            WAITFOR DELAY '00:00:00.100';  -- brief backoff, then retry
        END
        ELSE
            THROW;  -- not a deadlock, or out of retries
    END CATCH
END

Access tables and rows in a consistent order

Most deadlocks come from two transactions touching the same objects in the opposite order. If every transaction always updates row id = 1 before row id = 2 (and table A before table B), no cycle can form. Pick one canonical order and use it everywhere.

-- Both sessions update the lower id first, then the higher id.
BEGIN TRAN;
UPDATE dbo.Accounts SET balance = balance - 100 WHERE id = 1;
UPDATE dbo.Accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;

Keep transactions short and commit promptly

The longer a transaction holds locks, the more likely another session collides with it. Do validation and lookups before you open the transaction, keep only the writes inside it, and commit as soon as the work is done. Never wait for user input while a transaction is open.

-- Prepare values first, outside the transaction.
DECLARE @amount MONEY = 100;

-- Open the transaction only for the writes, then commit at once.
BEGIN TRAN;
UPDATE dbo.Accounts SET balance = balance - @amount WHERE id = 1;
UPDATE dbo.Accounts SET balance = balance + @amount WHERE id = 2;
COMMIT;

Add indexes so statements lock fewer rows

Without a useful index, an UPDATE or DELETE scans and locks far more rows than it changes, which widens the window for a deadlock. Index the columns in your WHERE clause so the engine seeks straight to the rows it needs and locks only those.

-- A seek on this index locks just the matching rows,
-- instead of a scan that locks the whole table.
CREATE INDEX IX_Accounts_CustomerId
    ON dbo.Accounts (customer_id);

Enable READ_COMMITTED_SNAPSHOT so readers do not block writers

Many deadlocks involve a reader and a writer blocking each other. Turning on Read Committed Snapshot Isolation (RCSI) makes readers use row versions instead of shared locks, so a SELECT no longer waits on a writer. This removes a large class of deadlocks with no code change.

ALTER DATABASE CURRENT SET READ_COMMITTED_SNAPSHOT ON
    WITH ROLLBACK IMMEDIATE;

Capture the deadlock graph to find the cycle

To fix a deadlock you first need to see which statements and resources form the cycle. Turn on trace flag 1222 to write the deadlock graph to the error log, or capture the xml_deadlock_report event with Extended Events, then read the graph to see exactly which two statements collided. See error 1222 for reading the graph output.

-- Write full deadlock details to the SQL Server error log.
DBCC TRACEON (1222, -1);

-- Or capture the deadlock graph with Extended Events.
CREATE EVENT SESSION deadlocks ON SERVER
    ADD EVENT sqlserver.xml_deadlock_report
    ADD TARGET package0.ring_buffer;
ALTER EVENT SESSION deadlocks ON SERVER STATE = START;

How to prevent it

Give every transaction the same, consistent access order for the tables and rows it touches, keep transactions short so locks are held only briefly, and index the columns in your WHERE clauses so statements lock fewer rows. Together these remove the conditions a deadlock needs to form. For the underlying mechanics, see transactions, locks and deadlocks and SQL transactions and ACID explained.

Because deadlocks can still happen occasionally under real concurrency, always add retry logic for error 1205 so the victim automatically reruns. Consider snapshot isolation (RCSI) so readers and writers stop blocking each other, and monitor with trace flag 1222 or Extended Events so you can spot and fix repeat offenders early.

Common questions

How do I fix SQL Server error 1205?

The victim transaction is already rolled back, so the immediate fix is to rerun it: catch error 1205 in a TRY/CATCH block or in the client and retry the whole transaction a few times. To stop deadlocks recurring, make all transactions access tables and rows in the same order, keep them short, and index the WHERE clause columns so fewer rows are locked.

Is error 1205 a sign of database corruption?

No. Error 1205 is normal behaviour under concurrency, not corruption and not a server fault. SQL Server detected that two transactions were stuck in a circular wait and deliberately killed the cheaper one to break the deadlock. The message even tells you to rerun the transaction, which usually succeeds on the next attempt.

Why was my transaction chosen as the deadlock victim?

SQL Server usually picks the transaction that is cheapest to roll back, meaning the one that has done the least log work so far. You can influence the choice with SET DEADLOCK_PRIORITY: a session with a lower priority is chosen as the victim before one with a higher priority.

How do I see which statements caused the deadlock?

Capture the deadlock graph. Turn on trace flag 1222 with DBCC TRACEON (1222, -1) to write the details to the error log, or capture the xml_deadlock_report event with Extended Events. The graph shows both processes, the statements they ran, and the lock resources that formed the cycle.

Still stuck on a SQL Server error?

Browse the full SQL Server error library, or get hands-on help from an experienced SQL professional.