Skip to content
MySQL

MySQL Error 1213

Deadlock found when trying to get lock; try restarting transaction

Applies to: MySQL 5.7, 8.0 and 8.4 with InnoDB tables (deadlock detection on by default, innodb_deadlock_detect)
Last technically reviewed 24 October 2026 on MySQL 8.0.46
The full message
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
Other forms of this message
PHP PDO
SQLSTATE[40001]: Serialization failure: 1213 Deadlock found when trying to get lock; try restarting transaction
SHOW ENGINE INNODB STATUS (LATEST DETECTED DEADLOCK section)
*** WE ROLL BACK TRANSACTION (1)
Error number
1213
SQLSTATE
40001
Symbol
ER_LOCK_DEADLOCK
Product
MySQL Server
Versions
MySQL 5.7, 8.0 and 8.4 with InnoDB tables (deadlock detection on by default, innodb_deadlock_detect)
Last reviewed
24 October 2026

What it means

Error 1213 means two or more transactions were each waiting for a lock the other held, so InnoDB broke the deadlock by rolling back one whole transaction, the one that received this error.

A deadlock happens when transaction A holds a lock that B needs while B holds a lock that A needs; neither can continue. InnoDB checks for this cycle every time a transaction has to wait (innodb_deadlock_detect, ON by default), so the error arrives at once rather than after a timeout. It picks a victim, rolls back that transaction entirely and returns 1213 to it. The other transaction then gets its lock and carries on as if nothing happened.

The MySQL manual says InnoDB tries to pick small transactions to roll back, measured by the number of rows inserted, updated or deleted. In our runs on 8.0.46, when both transactions had changed the same number of rows, the session whose statement completed the cycle received 1213; when that session had already changed more rows, the other session was rolled back instead. Do not rely on either: any transaction in the cycle can be the victim. SQLSTATE 40001 is the standard "serialization failure" code that frameworks use to decide a transaction can be retried. Note that SQL Server reports deadlocks as error 1205; in MySQL 1205 is the lock wait timeout.

Common causes

  • Two code paths update the same rows or tables in a different order, for example a transfer that debits account 1 then 2 running at the same time as one that debits 2 then 1.
  • Two transactions read the same row with SELECT ... FOR SHARE (or check a foreign key, which takes a shared lock) and then both try to update it, so each waits for the other's shared lock.
  • Range locks under REPEATABLE READ: locking reads, UPDATEs or DELETEs on ranges take next-key and gap locks, and concurrent INSERTs into those gaps collide.
  • Missing indexes make statements scan and lock many more rows than they change, which raises the chance that two transactions overlap.
  • Long transactions that touch many rows, which keep their locks for longer and collide with more concurrent work.

Diagnose it

Read-only These statements only read metadata (information_schema, performance_schema and SHOW statements) or your own data. They do not change data, privileges or configuration, so they are safe to run first.

Read the latest deadlock from InnoDB

Look for the LATEST DETECTED DEADLOCK section. It shows both transactions, the statement each was running, the locks each held (HOLDS THE LOCK(S)) and waited for (WAITING FOR THIS LOCK TO BE GRANTED), and which one was rolled back. Needs the PROCESS privilege.

SHOW ENGINE INNODB STATUS;
What to look for

Two (or more) transactions with the table, index and key values of the locks, ending in a line such as *** WE ROLL BACK TRANSACTION (1). Only the most recent deadlock is kept here; the section is absent if none has happened since the server started.

Count deadlocks and check the related settings

SELECT name, count
FROM information_schema.innodb_metrics
WHERE name = 'lock_deadlocks';

SHOW VARIABLES LIKE 'innodb_deadlock_detect';
SHOW VARIABLES LIKE 'innodb_print_all_deadlocks';
What to look for

The number of deadlocks since startup (watch whether it is rising), whether detection is on (ON by default) and whether every deadlock is written to the error log (OFF by default; then only the latest is visible in SHOW ENGINE INNODB STATUS).

See the locks current transactions hold

A deadlock is resolved at once, so you cannot catch it in progress, but the locks that normal transactions take show which rows and indexes they touch and in what order.

SELECT t.trx_mysql_thread_id, t.trx_started, t.trx_rows_modified,
       l.object_name, l.index_name, l.lock_mode, l.lock_status, l.lock_data
FROM information_schema.innodb_trx AS t
JOIN performance_schema.data_locks AS l
  ON l.engine_transaction_id = t.trx_id
ORDER BY t.trx_started, l.object_name;
What to look for

Each open transaction with its table and row locks. Locks on many rows, or lock_mode values without REC_NOT_GAP (next-key or gap locks), point to statements that lock more than they need.

Check that the statements in the deadlock use an index

EXPLAIN SELECT id, balance
FROM accounts
WHERE id = 2;
What to look for

type const, eq_ref, ref or range with a key named means few rows are locked. type ALL on a table in the deadlock means a full scan that locks every row it reads in a locking statement.

How to fix it

Each fix is labelled with what it changes. Try read-only checks and the least invasive fix first, and test changes outside production.

Retry the whole transaction

Client or network side

Deadlocks cannot be ruled out entirely under concurrency, and the MySQL manual advises being ready to re-issue a transaction that fails with one. InnoDB has already rolled back the victim's whole transaction, so start again from the beginning: re-read the data, repeat every statement and commit. Retry only on 1213 (or SQLSTATE 40001), a limited number of times with a short random delay, and log each occurrence. In PHP PDO our test showed inTransaction() still returning true after the error, so call rollBack() before retrying.

-- pseudocode for the application
-- for attempt in 1..3:
--     START TRANSACTION
--     run all statements of the unit of work
--     COMMIT, then stop
--     on error 1213: ROLLBACK, wait a few random milliseconds, try again
--     on any other error: ROLLBACK and report it

Touch rows and tables in the same order everywhere

Client or network side

If every transaction locks resources in one consistent order, transactions queue instead of deadlocking. For a transfer, update the account with the lower id first, whichever direction the money moves.

START TRANSACTION;
UPDATE accounts SET balance = balance - 10 WHERE id = LEAST(1, 2);   -- always the lower id first
UPDATE accounts SET balance = balance + 10 WHERE id = GREATEST(1, 2);
COMMIT;

Take the write lock first instead of upgrading a shared lock

Client or network side

When a transaction reads a row and then updates it, read it with FOR UPDATE rather than FOR SHARE. Two sessions then queue on the exclusive lock instead of both holding shared locks and deadlocking on the upgrade. Or do the change in one statement.

START TRANSACTION;
SELECT qty FROM stock WHERE sku = 'MUG-1' FOR UPDATE;
UPDATE stock SET qty = qty - 1 WHERE sku = 'MUG-1';
COMMIT;

-- or, in one statement
UPDATE stock SET qty = qty - 1 WHERE sku = 'MUG-1' AND qty > 0;

Lock fewer rows: index the conditions and keep transactions short

Changes schema

Index the columns used in UPDATE, DELETE and locking-read conditions so InnoDB locks only the rows it needs, commit straight after related changes, and split large batch jobs into small transactions. Where the application allows it, READ COMMITTED takes fewer gap locks than the default REPEATABLE READ, which the manual suggests for workloads with locking reads.

ALTER TABLE orders ADD INDEX ix_orders_customer (customer_id);

Log every deadlock while you investigate

Changes configuration

SHOW ENGINE INNODB STATUS keeps only the latest deadlock. Turning on innodb_print_all_deadlocks writes each one to the error log so you can find the recurring pair of statements; the manual advises turning it off again when you have finished debugging.

Caution: SET GLOBAL changes the server for every client and needs a privileged account; on a shared or managed server ask the administrator, and on a busy server expect the error log to grow while it is on.

SET GLOBAL innodb_print_all_deadlocks = ON;
-- later
SET GLOBAL innodb_print_all_deadlocks = OFF;

Examples

Two transfers update the same rows in opposite order

In our runs session B received 1213 (its transaction was rolled back) and session A's waiting UPDATE then completed. Both transactions were the same size; which one is chosen can differ.

CREATE TABLE accounts (
    id      INT PRIMARY KEY,
    balance DECIMAL(10,2) NOT NULL
);
INSERT INTO accounts VALUES (1, 100.00), (2, 50.00);

-- Session A
START TRANSACTION;
UPDATE accounts SET balance = balance - 10 WHERE id = 1;

-- Session B
START TRANSACTION;
UPDATE accounts SET balance = balance - 5 WHERE id = 2;

-- Session A: waits for B's lock on row 2
UPDATE accounts SET balance = balance + 10 WHERE id = 2;

-- Session B: needs A's lock on row 1, completing the cycle
UPDATE accounts SET balance = balance + 5 WHERE id = 1;

-- then ROLLBACK (or COMMIT) in both sessions
Result
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

Reproduced on MySQL 8.0.46, 24 October 2026.

Two sessions read with FOR SHARE, then both update the row

In our runs session B received 1213 and session A's UPDATE then went ahead.

CREATE TABLE stock (
    sku VARCHAR(20) PRIMARY KEY,
    qty INT NOT NULL
);
INSERT INTO stock VALUES ('MUG-1', 10);

-- Session A
START TRANSACTION;
SELECT qty FROM stock WHERE sku = 'MUG-1' FOR SHARE;

-- Session B
START TRANSACTION;
SELECT qty FROM stock WHERE sku = 'MUG-1' FOR SHARE;

-- Session A: needs an exclusive lock, waits for B's shared lock
UPDATE stock SET qty = qty - 1 WHERE sku = 'MUG-1';

-- Session B: needs an exclusive lock too, waits for A's shared lock
UPDATE stock SET qty = qty - 1 WHERE sku = 'MUG-1';

-- then ROLLBACK (or COMMIT) in both sessions
Result
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

Reproduced on MySQL 8.0.46, 24 October 2026.

The larger transaction survives, the smaller one is rolled back

Here session A received 1213 on its waiting UPDATE, and its first UPDATE was undone too: after the error A read balance 100.00 for row 1 again. Session B's last UPDATE completed. This matches the manual: InnoDB tries to roll back the smaller transaction.

CREATE TABLE accounts (
    id      INT PRIMARY KEY,
    balance DECIMAL(10,2) NOT NULL
);
INSERT INTO accounts VALUES (1, 100.00), (2, 50.00);
CREATE TABLE audit_log (
    id   INT AUTO_INCREMENT PRIMARY KEY,
    note VARCHAR(100)
);

-- Session A
START TRANSACTION;
UPDATE accounts SET balance = balance - 10 WHERE id = 1;

-- Session B: writes an audit row first, so it has changed more rows
START TRANSACTION;
INSERT INTO audit_log (note) VALUES ('transfer 2 to 1');
UPDATE accounts SET balance = balance - 5 WHERE id = 2;

-- Session A: waits for B's lock on row 2
UPDATE accounts SET balance = balance + 10 WHERE id = 2;

-- Session B: completes the cycle
UPDATE accounts SET balance = balance + 5 WHERE id = 1;

-- then ROLLBACK (or COMMIT) in both sessions
Result
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

Reproduced on MySQL 8.0.46, 24 October 2026.

How to prevent it

Design for deadlocks rather than hoping they never happen: wrap each unit of work in a transaction that can be retried safely, and retry it on 1213. Keep transactions short, access tables and rows in a fixed order in every code path, take the exclusive lock first (FOR UPDATE) when a read is followed by a write, and index the columns used in UPDATE, DELETE and locking-read conditions.

Monitor the lock_deadlocks counter in information_schema.innodb_metrics. If it rises, capture the deadlocks (SHOW ENGINE INNODB STATUS, or innodb_print_all_deadlocks for a while), find the pair of statements involved and change their order or locking, rather than only adding more retries.

Common questions

How do I fix MySQL error 1213 deadlock found?

First make the application retry the whole transaction on 1213, since InnoDB has already rolled it back. Then read the LATEST DETECTED DEADLOCK section of SHOW ENGINE INNODB STATUS to see which statements collided, and remove the cause: a consistent access order, FOR UPDATE instead of FOR SHARE before a write, better indexes or shorter transactions.

Is the whole transaction rolled back after a deadlock?

Yes. InnoDB rolls back the entire transaction of the victim, including the statements that ran before the one that got the error, and releases its locks. Do not continue the transaction or just repeat the last statement; start the transaction again from the beginning.

Which transaction does MySQL choose as the deadlock victim?

InnoDB tries to roll back the smaller transaction, measured by rows inserted, updated or deleted. In our tests the session that had changed fewer rows was rolled back, and with equal sizes the session that completed the cycle was. Your code should assume any transaction can be the victim.

Should I turn off innodb_deadlock_detect?

Almost never. The manual describes disabling it only for very high concurrency systems where detection itself slows things down; deadlocks are then resolved only by innodb_lock_wait_timeout, so they show up as slow 1205 errors instead of immediate 1213 errors.

Learn more on CodeWithSQL

Official documentation

Last technically reviewed 24 October 2026; examples and diagnostics run on MySQL 8.0.46. Message templates checked against the server's error catalogue (perror) for that version.

Still stuck on a MySQL error?

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