Does a successful database connection mean the database is ready?
No.
A connection proves TCP, authentication, and that the named database exists. It says nothing about whether the schema was applied. An empty database — zero tables — accepts a connection pool happily, so a health check that only pings can return OK while every feature that needs a table is broken.
The readiness check has to ask one more question: is the schema at the expected migration version?
The Gap Between "Connected" and "Ready"
The API server started. The database connection pool opened successfully. The server had a database. Every startup check saw something true: the pool was non-nil, the database was reachable, authentication succeeded.
None of those things mean the schema exists.
The connection pool validates TCP and auth, not DDL. A pgxpool.Pool connects to a named database. That database can be empty. Pool creation still succeeds. Every init function that checks queries != nil gets true, because the queries object wraps the pool, and the pool exists. Table existence is only tested when actual SQL runs at request time.
The health endpoint checked two questions: is the server process running, and can the DB pool ping? Both answers were yes. Neither answer touched whether the 22 migrations had been applied, whether the tables the application depends on existed, or whether any feature that writes to the database could work.
The result was {"status":"ok"} while every database-backed feature — audit trail, access controls, configuration, multi-factor authentication enforcement — was silently broken. Three days later, a human ran \dt and found no relations.
The Distinction That Fixes It
Liveness means the process is running. Readiness means the process can serve traffic correctly.
A health endpoint that checks liveness and labels it readiness is the failure pattern. The fix is simple: on startup, verify the schema version matches the expected migration count. Add the same check to the readiness response. "Connected" and "schema current" are different facts; report both.
The broader rule is not about PostgreSQL. A successful connection to a dependency tells you the dependency is reachable. It tells you nothing about whether the dependency is in the state your application requires.
When a connection check is all you need
For a pure liveness probe — "is the process up and the socket open?" — a connection ping is exactly the right, cheap check. The bug is not the ping. The bug is using a liveness answer to make a readiness decision. Keep both, and label which question each one answers.
Treat connection and readiness as separate assertions — and make your health endpoint report both.
About AmanERP
AmanERP is an AI-native ERP for SMBs, built in public, where health checks answer the question that matters: ready, not merely running. Aman means peace — calm software, honestly reported. www.amanerp.com
