What it means
This is libpq, the client library, talking: it was reading from the server and the connection ended. There’s no SQLSTATE, because the server didn’t send an error, or didn’t get the chance:
server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
Over TLS the same event is worded differently. A client built with OpenSSL 3 says
SSL error: unexpected eof while reading; one built with an older OpenSSL says
SSL SYSCALL error: EOF detected, because OpenSSL 3 changed how it reports a connection that ends
without a TLS goodbye. When the server sent a message before closing, the TLS wording is
SSL connection has been closed unexpectedly.
What matters is what came before it. If the server said why, its message is printed first:
FATAL: terminating connection due to administrator command
(its page), an
idle-in-transaction timeout, or this one, sent to
every other session when one server process crashes:
WARNING: terminating connection because of crash of another server process
DETAIL: The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
HINT: In a moment you should be able to reconnect to the database and repeat your command.
If nothing came before it, the server process vanished or the network dropped the connection. Either way, the transaction you were in is gone (rolled back), and you need a new connection.
Common causes
- The server process was killed, most often by the Linux out-of-memory killer, or a container memory limit, during a big query. When one server process dies like that, PostgreSQL restarts all of them, so every session is dropped.
- The server restarted or crashed: a crash, a restart for maintenance or a failover, a container that was stopped or redeployed.
- An idle connection dropped by something in between: a NAT gateway, firewall, load balancer or VPN that forgets connections idle for a few minutes. The next query finds it dead.
- A pooler or proxy (PgBouncer, a cloud proxy) closing server-side or client-side connections it considers too old or idle.
How to fix it
Read the server log first
It tells the causes apart. A killed process looks like this:
LOG: client backend (PID 100) was terminated by signal 9: Killed
LOG: terminating any other active server processes
LOG: all server processes terminated; reinitializing
followed by database system was not properly shut down; automatic recovery in progress. If the
log shows nothing at that time, the server didn’t drop you; something on the network did.
If processes are killed for memory
Signal 9 on Linux is usually the out-of-memory killer (dmesg or the container runtime’s events
confirm it). Look at what was running: a query with a huge sort or hash, many parallel workers, or
a large work_mem multiplied by many connections. Lower work_mem for that work, fix the query,
reduce max_connections or use a pooler, or give the server more memory. The PostgreSQL
documentation describes setting vm.overcommit_memory = 2 on Linux, so that the kernel refuses an
allocation (which PostgreSQL reports as an out of memory error) instead of killing a process.
If idle connections are dropped
Turn on TCP keepalives so the connection never looks idle to the network, from the client:
postgresql://<user>@<host>/<database>?keepalives=1&keepalives_idle=60&keepalives_interval=10&keepalives_count=5
or on the server, with tcp_keepalives_idle and friends. Also set your connection pool’s idle
timeout and maximum lifetime below the network’s timeout, and have it test connections before use.
Always be ready to reconnect
Restarts and failovers happen. Applications should catch a lost connection, open a new one, and
retry the whole transaction, not only the last statement. One exception: if the connection dropped
while COMMIT was in flight, you can’t tell whether it committed, so check before you run it again.
Reproduce it
In a throwaway PostgreSQL 18.6 container with TLS on, two sessions ran SELECT pg_sleep(10): one
over TLS, one without (sslmode=disable). We killed the first one’s server process with
kill -9. The TLS session got:
SSL error: unexpected eof while reading
connection to server was lost
The other session, untouched, was dropped too, because PostgreSQL restarts every process after one crashes:
WARNING: terminating connection because of crash of another server process
DETAIL: The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
HINT: In a moment you should be able to reconnect to the database and repeat your command.
server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
connection to server was lost
The server log showed the three lines above, then automatic recovery, and
database system is ready to accept connections about 0.3 seconds later. Our psql 18.6 is built
with OpenSSL 3, so it printed the unexpected eof wording; we didn’t have a client built with an
older OpenSSL to show SSL SYSCALL error: EOF detected.
In Inlet
When Inlet’s connection is lost, it shows the error, and What this error means opens this page. Inlet’s Activity monitor lists the server’s sessions, so after a restart you can see which applications have reconnected.