alibaba/druid · error · SQLException
connection closed
Error message
connection closed
What it means
Thrown by DruidPooledConnection.checkStateInternal() when the connection is closed AND a disableError is set. The disableError (the exception that caused Druid to disable the connection) is chained as cause, giving you the original failure (e.g. a fatal DB error) alongside the 'closed' status.
Source
Thrown at core/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java:1176
asyncCloseEnabled = false;
}
if (asyncCloseEnabled) {
lock.lock();
try {
checkStateInternal();
} finally {
lock.unlock();
}
} else {
checkStateInternal();
}
}
private void checkStateInternal() throws SQLException {
if (closed) {
if (disableError != null) {
throw new SQLException("connection closed", disableError);
} else {
throw new SQLException("connection closed");
}
}
if (disable) {
if (disableError != null) {
throw new SQLException("connection disabled", disableError);
} else {
throw new SQLException("connection disabled");
}
}
if (holder == null) {
if (disableError != null) {
throw new SQLException("connection holder is null", disableError);
} else {
throw new SQLException("connection holder is null");View on GitHub (pinned to fa8dc99126)
Solutions
- Always use try-with-resources for Connection/Statement/ResultSet so a closed connection is never used again.
- Read the chained disableError to find why Druid closed it (fatal SQL error, validation failure) and fix the upstream cause.
- Avoid holding a Connection across method/RPC boundaries where async-close or eviction can reclaim it.
- If asyncCloseConnectionEnable is on and causing races, review whether you need it; ensure statements complete before returning the connection.
Example fix
// before — connection reused after a fatal error closed it
Connection c = pool.borrow();
runQuery(c); // fatal error -> c closed
runQuery(c); // SQLException("connection closed", disableError)
// after — fresh connection each unit of work
try (Connection c = pool.borrow()) {
runQuery(c);
} Defensive patterns
Strategy: validation
Validate before calling
if (pooledConn.isClosed()) {
Throwable why = pooledConn.getDisableError();
throw new IllegalStateException("connection already closed" + (why == null ? "" : ": " + why));
}
// proceed to use the connection Type guard
boolean usable = pooledConn != null && !pooledConn.isClosed()
&& !pooledConn.isDisable() && pooledConn.getHolder() != null; Try / catch
try {
pooledConn.createStatement();
} catch (SQLException e) {
if ("connection closed".equals(e.getMessage()) && e.getCause() != null) {
// disableError explains why Druid closed it; borrow fresh
log.error("conn closed by Druid due to: {}", e.getCause());
borrowFreshAndRetry();
} else throw e;
} Prevention
- Always scope Connection in try-with-resources so it is never used after close.
- Read disableError to learn why Druid closed the connection and fix the root cause.
- Do not hold connections across async-close or eviction windows.
When it happens
Trigger: Any JDBC operation on a DruidPooledConnection whose closed flag is true and disableError is non-null triggers checkState() -> checkStateInternal(), throwing at line 1176. Typically the connection was closed by Druid's async-close / keep-alive / fatal-error handling after a detected failure, and the application still holds a stale reference.
Common situations: Using a connection after handleFatalError disabled and closed it (exceptionSorter flagged a fatal error); keepAlive/eviction closed an idle connection the app still references; async-close (asyncCloseConnectionEnable) racing with a slow statement; a connection returned to a caller after the pool reclaimed it; leaked connection reused across requests.
Understand the failure class
- Connection failures: ECONNREFUSED, ECONNRESET, and friends — why connections get refused, reset, or dropped.
Related errors
- connection disabled
- onFatalError, activeCount {}, onFatalErrorMaxActive {}
- wait millis {waitMillis}, active {activeCount}, maxActive {m
- dataSource already closed at {date}
- connection holder is null
AI-assisted analysis of alibaba/druid@fa8dc99126 (2026-08-14).
Data as JSON: /api/errors/4da1530d599ae33c.
Report an issue: GitHub.