hibernate/hibernate-orm · error · HibernateException

Connection lock-timeout does not accept no-wait

Error message

Connection lock-timeout does not accept no-wait

What it means

On MySQL, Hibernate sets pessimistic-lock timeouts through 'SET @@SESSION.innodb_lock_wait_timeout = N'. The variable is in whole seconds with allowed range [1, 1073741824], so the no-wait magic value 0 ms (Timeouts.NO_WAIT_MILLI) has no representable value and MySQLLockingSupport throws this HibernateException instead of rounding to 1 second (which would silently wait instead of failing fast). MySQL reports Level.SUPPORTED, not EXTENDED, so no-wait is never accepted here.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/dialect/lock/internal/MySQLLockingSupport.java:139

					},
					connection,
					factory
			);
		}

		@Override
		public void setLockTimeout(Timeout timeout, Connection connection, SessionFactoryImplementor factory) {
			Helper.setLockTimeout(
					timeout,
					(t) -> {
						// see https://dev.mysql.com/doc/refman/8.4/en/innodb-parameters.html#sysvar_innodb_lock_wait_timeout
						// unit: seconds, allowed values: [1, 1073741824]
						final int milliseconds = timeout.milliseconds();
						if ( milliseconds == SKIP_LOCKED_MILLI ) {
							throw new HibernateException( "Connection lock-timeout does not accept skip-locked" );
						}
						if ( milliseconds == NO_WAIT_MILLI ) {
							throw new HibernateException( "Connection lock-timeout does not accept no-wait" );
						}
						if ( milliseconds == WAIT_FOREVER_MILLI ) {
							return foreverValue;
						}
						return (int) Math.ceil( (double) milliseconds / 1000);
					},
					"SET @@SESSION.innodb_lock_wait_timeout = %s",
					connection,
					factory
			);
		}
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Use the smallest real timeout (>= 1 second via innodb_lock_wait_timeout) and handle LockTimeoutException to fail fast, or WAIT_FOREVER (-1) to wait
  2. If true no-wait is required, use a native 'SELECT ... FOR UPDATE NOWAIT' (MySQL 8+) outside the connection-timeout path
  3. Guard with getConnectionLockTimeoutStrategy().getSupportedLevel(): no-wait requires Level.EXTENDED (SQL Server/Sybase only)
  4. Audit and remove lock timeout hints set to 0 in configuration or query hints

Example fix

// before
Map<String, Object> hints = Map.of("jakarta.persistence.lock.timeout", 0); // NO_WAIT -> throws
Order o = em.find(Order.class, id, LockModeType.PESSIMISTIC_WRITE, hints);

// after: 1s wait, catch the timeout to emulate no-wait behavior
Map<String, Object> hints = Map.of("jakarta.persistence.lock.timeout", 1000);
try {
    Order o = em.find(Order.class, id, LockModeType.PESSIMISTIC_WRITE, hints);
} catch (PessimisticLockException e) { /* row busy: fail fast */ }
Defensive patterns

Strategy: validation

Validate before calling

int millis = lockOptions.getTimeOut();
if (millis <= 0) { // 0 = no-wait, -1 = forever, -2 = skip-locked
    // only WAIT_FOREVER (-1) or >=1000ms make sense for MySQL connection timeouts
    lockOptions.setTimeOut(millis == Timeouts.WAIT_FOREVER_MILLI ? -1 : 1000);
}

Type guard

static boolean acceptsConnectionTimeout(ConnectionLockTimeoutStrategy s, int millis) {
    if (s.getSupportedLevel() == ConnectionLockTimeoutStrategy.Level.NONE) return false;
    if (millis == Timeouts.SKIP_LOCKED_MILLI) return false;
    return millis != Timeouts.NO_WAIT_MILLI
            || s.getSupportedLevel() == ConnectionLockTimeoutStrategy.Level.EXTENDED;
}

Try / catch

try {
    Order o = em.find(Order.class, id, LockModeType.PESSIMISTIC_WRITE, hints);
} catch (HibernateException e) {
    if (e.getMessage() != null && e.getMessage().contains("does not accept no-wait")) {
        hints = Map.of("jakarta.persistence.lock.timeout", 1000);
        em.find(Order.class, id, LockModeType.PESSIMISTIC_WRITE, hints);
    } else { throw e; }
}

Prevention

When it happens

Trigger: session.buildLockRequest(LockOptions.UPGRADE_NOWAIT).lock(entity) or lockOptions.setTimeOut(0); em.find(id, PESSIMISTIC_WRITE) / query locking with hint 'jakarta.persistence.lock.timeout' = 0; Timeouts.NO_WAIT reaching setLockTimeout on MySQL, MariaDB or TiDB dialects that route timeouts through the connection.

Common situations: 'Fail fast' locking recipes copied from JPA documentation that set lock.timeout=0; global persistence.xml property 'jakarta.persistence.lock.timeout'=0 applied to all locks; moving an app from SQL Server/Oracle (where no-wait works) to MySQL; library code shared across databases assuming no-wait is universal.

Understand the failure class

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/d4a1b261846e814f. Report an issue: GitHub.