MySQL returns ER_USER_LOCK_DEADLOCK (error 3058, SQLSTATE HY000) when GET_LOCK or RELEASE_LOCK enters a mutual wait, causing a user-level lock deadlock.
ER_USER_LOCK_DEADLOCK appears when two sessions wait on each other’s named locks. Release or time-out conflicting locks, commit or roll back open transactions, and retry GET_LOCK to resolve the deadlock.
ER_USER_LOCK_DEADLOCK
The message Deadlock found when trying to get user-level lock means MySQL detected a cyclic wait between sessions using GET_LOCK or RELEASE_LOCK. Each session is holding a named lock that the other needs, so progress halts until the server intervenes.
Since version 5.7.5 MySQL aborts one participant, rolls back its statement, and returns error 3058 with SQLSTATE HY000. The connection remains open, but the failed lock was not acquired.
Most cases arise when application threads rely on the same lock names for different tasks without a strict ordering policy. Concurrent GET_LOCK calls with overlapping names can quickly form a cycle.
Long transactions that keep metadata locks open compound the problem, because GET_LOCK waits while table-level locks from the other session remain active.
Choose one blocked session as the survivor, explicitly RELEASE_LOCK in the other, and retry. If retry logic already exists, simply catch error 3058 and run GET_LOCK again after a short sleep.
Reduce risk by keeping named-lock scope narrow: acquire just before the critical section and release immediately afterward or by COMMIT.
Background workers inserting into the same queue table often use GET_LOCK('queue_write'). Stagger their schedules or use lock names derived from primary keys to avoid contention.
Online schema changes that rely on metadata locks can collide with application-level GET_LOCK calls. Run DDL in maintenance windows or separate connections that never request user locks.
Adopt a global naming convention that encodes resource hierarchy, eg project:task:id, so sessions acquire locks in identical order.
Set a low timeout on GET_LOCK calls, e.g., 2 seconds, to let applications fail fast and retry rather than hang indefinitely.
ER_LOCK_DEADLOCK (1213) is similar but occurs with row or metadata locks, not user-level locks. Handle it by rolling back and retrying the entire transaction.
Different code paths request the same lock names simultaneously without coordination.
Sessions keep metadata or table locks open, blocking subsequent GET_LOCK attempts.
Applications acquire multiple named locks in varying sequences, creating circular wait chains.
Indefinite waits allow cycles to persist long enough for the server to detect a deadlock.
Deadlock detected among transactional row locks; resolved by rolling back one transaction.
Row or metadata lock wait exceeded innodb_lock_wait_timeout.
Metadata lock failed to be released before timeout during online DDL.
Only the statement requesting GET_LOCK is aborted. Open transactions remain active unless you explicitly roll back.
No. You can avoid them by refactoring code but MySQL provides no server flag to disable GET_LOCK.
Set a small value, such as 2 seconds, to minimize impact and allow quick retries.
Galaxy’s query history highlights aborted statements, helping you spot frequent ER_USER_LOCK_DEADLOCK errors and refactor lock usage patterns.