{"record":{"id":"6344c64062f9ac41","repo":"hibernate/hibernate-orm","slug":"connection-lock-timeout-does-not-accept-skip-locke-6344c6","errorCode":null,"errorMessage":"Connection lock-timeout does not accept skip-locked","messagePattern":"Connection lock-timeout does not accept skip-locked","errorType":"exception","errorClass":"HibernateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/lock/internal/MySQLLockingSupport.java","lineNumber":136,"sourceCode":"\t\t\t\t\t\t// unit: seconds, allowed values: [1, 1073741824]\n\t\t\t\t\t\tfinal int seconds = resultSet.getInt( 1 );\n\t\t\t\t\t\treturn seconds == foreverValue ? Timeouts.WAIT_FOREVER : Timeout.seconds( seconds );\n\t\t\t\t\t},\n\t\t\t\t\tconnection,\n\t\t\t\t\tfactory\n\t\t\t);\n\t\t}\n\n\t\t@Override\n\t\tpublic void setLockTimeout(Timeout timeout, Connection connection, SessionFactoryImplementor factory) {\n\t\t\tHelper.setLockTimeout(\n\t\t\t\t\ttimeout,\n\t\t\t\t\t(t) -> {\n\t\t\t\t\t\t// see https://dev.mysql.com/doc/refman/8.4/en/innodb-parameters.html#sysvar_innodb_lock_wait_timeout\n\t\t\t\t\t\t// unit: seconds, allowed values: [1, 1073741824]\n\t\t\t\t\t\tfinal int milliseconds = timeout.milliseconds();\n\t\t\t\t\t\tif ( milliseconds == SKIP_LOCKED_MILLI ) {\n\t\t\t\t\t\t\tthrow new HibernateException( \"Connection lock-timeout does not accept skip-locked\" );\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( milliseconds == NO_WAIT_MILLI ) {\n\t\t\t\t\t\t\tthrow new HibernateException( \"Connection lock-timeout does not accept no-wait\" );\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( milliseconds == WAIT_FOREVER_MILLI ) {\n\t\t\t\t\t\t\treturn foreverValue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn (int) Math.ceil( (double) milliseconds / 1000);\n\t\t\t\t\t},\n\t\t\t\t\t\"SET @@SESSION.innodb_lock_wait_timeout = %s\",\n\t\t\t\t\tconnection,\n\t\t\t\t\tfactory\n\t\t\t);\n\t\t}\n\t}\n}\n","sourceCodeStart":118,"sourceCodeEnd":153,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/lock/internal/MySQLLockingSupport.java#L118-L153","documentation":"On MySQL, Hibernate applies pessimistic-lock timeouts by executing 'SET @@SESSION.innodb_lock_wait_timeout = N' (MySQLLockingSupport.ConnectionLockTimeoutStrategyImpl). That server variable is measured in whole seconds with a minimum of 1, so the magic value SKIP_LOCKED (-2 ms) cannot be mapped and MySQLLockingSupport throws this HibernateException rather than silently waiting. The strategy reports Level.SUPPORTED (not EXTENDED): skip-locked is never expressible through the connection setting, even though MySQL 8 supports SKIP LOCKED as a locking clause.","triggerScenarios":"session.buildLockRequest(LockOptions.UPGRADE_SKIPLOCKED).lock(entity) / lockOptions.setTimeOut(-2); em.find(id, PESSIMISTIC_WRITE, hints) or query.setLockMode(PESSIMISTIC_WRITE) with 'jakarta.persistence.lock.timeout' = -2; Timeouts.SKIP_LOCKED reaching setLockTimeout when the dialect uses connection-level timeouts. Also applies to MariaDB/TiDB variants reusing this strategy.","commonSituations":"Queue/poller code written for PostgreSQL (SELECT ... FOR UPDATE SKIP LOCKED) ported to MySQL with the same LockOptions; global lock timeout hint -2 in persistence.xml or Spring Data JPA repository hints; switching databases without adjusting lock timeout magic values; Hibernate 6 -> 7 upgrades where the timeout plumbing changed.","solutions":["Use a real positive timeout in ms (it will be rounded up to seconds) or WAIT_FOREVER (-1) on MySQL","Express skip-locked through the locking clause instead: rely on LockMode UPGRADE_SKIPLOCKED with a dialect/locking-clause strategy that emits 'FOR UPDATE SKIP LOCKED', or a native query","Check getConnectionLockTimeoutStrategy().getSupportedLevel() before relying on magic timeout values - only EXTENDED (SQL Server/Sybase) supports no-wait, none support skip-locked","Scope 'jakarta.persistence.lock.timeout' hints so they are not applied globally with value -2"],"exampleFix":"// before\nMap<String, Object> hints = Map.of(\"jakarta.persistence.lock.timeout\", -2); // SKIP_LOCKED -> throws\nList<Order> orders = em.createQuery(...).setLockMode(LockModeType.PESSIMISTIC_WRITE)\n        .setHints(hints).getResultList();\n\n// after: short real wait (rounded up to 1s by innodb_lock_wait_timeout)\nMap<String, Object> hints = Map.of(\"jakarta.persistence.lock.timeout\", 1000);\nList<Order> orders = em.createQuery(...).setLockMode(LockModeType.PESSIMISTIC_WRITE)\n        .setHints(hints).getResultList();","handlingStrategy":"validation","validationCode":"int millis = lockOptions.getTimeOut();\nif (millis == Timeouts.SKIP_LOCKED_MILLI\n        || (millis == Timeouts.NO_WAIT_MILLI\n            && strategy.getSupportedLevel() != ConnectionLockTimeoutStrategy.Level.EXTENDED)) {\n    lockOptions.setTimeOut(1000); // innodb_lock_wait_timeout works in whole seconds >= 1\n}","typeGuard":"static boolean acceptsConnectionTimeout(ConnectionLockTimeoutStrategy s, int millis) {\n    if (s.getSupportedLevel() == ConnectionLockTimeoutStrategy.Level.NONE) return false;\n    if (millis == Timeouts.SKIP_LOCKED_MILLI) return false;\n    return millis != Timeouts.NO_WAIT_MILLI\n            || s.getSupportedLevel() == ConnectionLockTimeoutStrategy.Level.EXTENDED;\n}","tryCatchPattern":"try {\n    query.setLockMode(LockModeType.PESSIMISTIC_WRITE).getResultList();\n} catch (HibernateException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"lock-timeout does not accept\")) {\n        // magic timeout rejected by innodb_lock_wait_timeout path: adjust and retry\n    } else { throw e; }\n}","preventionTips":["Remember innodb_lock_wait_timeout is seconds with minimum 1: no-wait/skip-locked cannot be expressed through it","Use locking clauses (FOR UPDATE SKIP LOCKED / NOWAIT) or native SQL for those semantics on MySQL 8+","Keep lock timeout hints out of shared/global config","Add per-dialect locking tests to CI"],"tags":["mysql","pessimistic-locking","lock-timeout","skip-locked","hibernate"],"backgroundTag":"pessimistic-lock-timeout-unsupported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}