PostgreSQL raises SQLSTATE 08003 (connection_does_not_exist) when a command is executed against a connection that has already been closed, was terminated by the server, or was never successfully established. The error typically surfaces as:
ERROR: connection does not exist
In application logs you may also see driver-level wrappers such as FATAL: terminating connection due to administrator command followed by a subsequent 08003 when the application attempts to reuse the dead handle.
What This Error Means
SQLSTATE 08003 belongs to class 08 — Connection Exception — which covers all errors related to the state of the physical or logical connection between a client and the PostgreSQL server. Class 08 errors are distinct from query-level errors: they indicate that no valid connection exists through which a query can be executed, rather than a problem with the query itself.
PostgreSQL raises this condition in the server-side PL/pgSQL runtime when code calls dblink or similar connection-oriented functions (e.g., dblink_exec, dblink_fetch, dblink_close) and the named connection handle is not present in the current session's connection list. On the client side, drivers such as libpq translate a lost TCP connection or an EOF from the server into this same SQLSTATE before surfacing it to the application layer.
After this error occurs the current connection is effectively unusable. Any open transaction is rolled back and the client must obtain a new connection — either by reconnecting directly or by acquiring a fresh handle from a connection pool.
Common Causes
Stale dblink connection handle. A session opened a named
dblinkconnection withdblink_connect('myconn', ...)but later tried to use it after the connection was closed (viadblink_disconnect) or after the session that created it ended.Connection closed by the server. The PostgreSQL server terminated the backend — due to
pg_terminate_backend(),idle_in_transaction_session_timeout,statement_timeout, a crash, or a planned restart — while the client still held a reference to the socket.Network interruption. A firewall, load balancer, or NAT gateway silently dropped the TCP connection (e.g., idle-timeout). The client process did not detect the disconnect until it attempted to send the next command.
Connection pool returning a dead connection. A connection pooler (PgBouncer, application-level pool) returned a connection that had already been terminated server-side. This is common when
server_idle_timeoutortcp_keepalivesare not configured properly.Calling dblink functions without an open connection. Code calls
dblink_exec('myconn', ...)beforedblink_connect('myconn', ...)has been called in the current session, or afterdblink_disconnect('myconn')was already called.
How to Fix connection_does_not_exist
Validate dblink connections before use. Query
dblink_get_connections()to confirm the named connection exists before issuing commands against it:-- Check whether the connection exists before using it DO $$ BEGIN IF NOT ('myconn' = ANY(dblink_get_connections())) THEN PERFORM dblink_connect('myconn', 'dbname=targetdb host=10.0.0.5'); END IF; END; $$; SELECT * FROM dblink('myconn', 'SELECT id, name FROM orders') AS t(id int, name text);Enable TCP keepalives in libpq. Configure
keepalives,keepalives_idle,keepalives_interval, andkeepalives_countin your connection string orpostgresql.confso that dead connections are detected quickly rather than silently reused:postgresql://user:pass@host/db?keepalives=1&keepalives_idle=30&keepalives_interval=10&keepalives_count=5Handle reconnection in application code. Catch
08003(and the related08006,08001) at the application layer and retry with a fresh connection. Most connection pool libraries do this automatically when configured correctly — ensuretest_on_borrowor equivalent validation is enabled.Configure PgBouncer server-side timeouts. In
pgbouncer.ini, setserver_idle_timeoutandserver_lifetimeso that pooled connections are proactively recycled before the server closes them:server_idle_timeout = 600 server_lifetime = 3600 server_reset_query = DISCARD ALLAvoid holding dblink connections across transactions. Open and close
dblinkconnections within the same function or explicit transaction block. Do not rely on a connection remaining open across multiple unrelated calls in the same session.Increase
idle_in_transaction_session_timeoutawareness. If your server is set to kill idle-in-transaction sessions, ensure application code does not leave connections in an open transaction while waiting for external events.
Additional Information
- SQLSTATE class
08— Connection Exception — includes several related codes:08000(connection exception, generic),08001(sqlclient unable to establish sqlconnection),08004(sqlserver rejected establishment of sqlconnection),08006(connection failure), and08007(transaction resolution unknown).08003is specific to referencing a connection that does not exist. - The
dblinkextension is the most common server-side trigger for08003in PostgreSQL. Foreign Data Wrappers (FDW) usingpostgres_fdwmanage connections internally and are less likely to surface raw08003errors to user code, but08006can still appear when the remote server is unreachable. - Most PostgreSQL client drivers (psycopg2, asyncpg, JDBC, node-postgres) map
08003to a specific exception class (e.g.,psycopg2.OperationalError) and include the SQLSTATE in the exception'spgcodeattribute, making it straightforward to catch and handle selectively. - This error does not indicate data corruption. It is purely a connection-lifecycle issue and is safe to retry after re-establishing the connection.
Frequently Asked Questions
Why does this error appear suddenly after the application has been running fine for hours? Most often this is a silent TCP connection drop caused by a firewall or NAT idle-timeout. The connection appears alive to the client until the first command is sent after the timeout, at which point the server has already discarded the backend process. Enabling TCP keepalives (see fix #2 above) causes the OS to detect and report the dead connection much sooner.
Does 08003 always mean I need to reconnect?
Yes. Once this SQLSTATE is returned, the connection handle is unusable. You must close it and open a new connection. Attempting to reuse the same handle will result in the same error or undefined behavior depending on the driver.
Why does this happen with dblink but not with regular queries?
Regular client queries go over the client's own session connection, which libpq manages. dblink creates additional named connections from within a PostgreSQL session to remote (or even the same) databases. These secondary connections have their own lifecycle and are not automatically cleaned up when a transaction rolls back, making them more vulnerable to being referenced after they have been closed.
How can I tell which dblink connections are currently open in my session?
Use SELECT dblink_get_connections();. This returns an array of names for all open dblink connections in the current session. An empty array or a missing name means the connection you are trying to use has not been established or has already been disconnected.