hibernate/hibernate-orm · error · SchemaManagementException

Could not build JDBC Connection context to drop schema on…

Error message

Could not build JDBC Connection context to drop schema on SessionFactory close

What it means

With hibernate.hbm2ddl.auto=create-drop the DROP is deferred until SessionFactory close (DelayedDropAction). At close, Hibernate rebuilds a JDBC context via JdbcServices.getBootstrapJdbcConnectionAccess(); if the configured connection provider exposes no bootstrap connection access (null), it cannot obtain a connection to run the drop and throws this SchemaManagementException from the shutdown path. It is a configuration incompatibility, not a network failure.

Solutions

  1. Switch hibernate.hbm2ddl.auto from create-drop to create or none in environments whose connection provider has no bootstrap JDBC access, and drop schema explicitly when needed.
  2. Run schema generation in a bootstrap phase that uses a plain DataSource/DriverManager-based connection provider, then disable hbm2ddl for the tenant-scoped runtime.
  3. Instead of delayed drop, generate a drop script once (SchemaExport, TargetType.SCRIPT) and apply it from CI/cleanup tooling.

Example fix

// before
<property name="hibernate.hbm2ddl.auto" value="create-drop"/> <!-- multi-tenant connection provider -->

// after
<property name="hibernate.hbm2ddl.auto" value="none"/>
<!-- generate ddl at build time via SchemaExport and manage drops out-of-band -->
Defensive patterns

Strategy: validation

Validate before calling

JdbcServices jdbc = serviceRegistry.requireService(JdbcServices.class);
if (jdbc.getBootstrapJdbcConnectionAccess() == null) {
    // create-drop cannot run its delayed drop here: switch it off before building the factory
    cfg.setProperty(AvailableSettings.HBM2DDL_AUTO, Action.NONE.getExternalName());
}

Try / catch

try {
    sessionFactory.close();
} catch (SchemaManagementException e) {
    if (e.getMessage() != null && e.getMessage().contains("drop schema on SessionFactory close")) {
        // delayed drop could not run; drop the schema out-of-band, then finish shutdown
    } else { throw e; }
}

Prevention

When it happens

Trigger: create-drop combined with a ConnectionProvider whose getBootstrapJdbcConnectionAccess() yields null: multi-tenant setups backed by a MultiTenantConnectionProvider, user-supplied connections, or custom connection providers that only serve tenant/user-scoped connections. The exception is thrown while the SessionFactory is closing, out of the JdbcContextDelayedDropImpl constructor.

Common situations: Multi-tenant applications that kept create-drop from a single-tenant prototype; Spring Boot tests wiring a tenant-aware DataSource into hbm2ddl; demos run with externally provided Connections; custom connection providers migrated from Hibernate 5 where this path behaved differently.

Related errors


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

Appendix: source

Thrown at hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaDropperImpl.java:645

				}
			}
			finally {
				target.release();
			}
		}

		private static class JdbcContextDelayedDropImpl implements JdbcContext {
			private final ServiceRegistry serviceRegistry;
			private final JdbcServices jdbcServices;
			private final JdbcConnectionAccess jdbcConnectionAccess;

			public JdbcContextDelayedDropImpl(ServiceRegistry serviceRegistry) {
				this.serviceRegistry = serviceRegistry;
				this.jdbcServices = serviceRegistry.requireService( JdbcServices.class );
				this.jdbcConnectionAccess = jdbcServices.getBootstrapJdbcConnectionAccess();
				if ( jdbcConnectionAccess == null ) {
					// todo : log or error?
					throw new SchemaManagementException(
							"Could not build JDBC Connection context to drop schema on SessionFactory close"
					);
				}
			}

			@Override
			public JdbcConnectionAccess getJdbcConnectionAccess() {
				return jdbcConnectionAccess;
			}

			@Override
			public Dialect getDialect() {
				return jdbcServices.getJdbcEnvironment().getDialect();
			}

			@Override
			public SqlStatementLogger getSqlStatementLogger() {
				return jdbcServices.getSqlStatementLogger();

View on GitHub (pinned to fad1729dce)