Database drivers expose TLS connection modes such as 'require', 'verify-ca' and 'verify-full'. What does each one actually check, and which of them stop an attacker who can intercept the connection?
answer
- prefer/allow = silent plaintext fallback
- require = encrypted, unauthenticated
- verify-ca = chain only, any cert from that CA wins
- verify-full = chain + hostname
- CA bundle must be shipped with the app
basics
~20 s'require' encrypts but validates nothing, so any impostor with any certificate is accepted. 'verify-ca' checks the certificate chains to a trusted CA but not the hostname. 'verify-full' checks the chain and that the certificate names the host you dialled. Only verify-full stops a man-in-the-middle.
solid answer
~50 sThe modes form a ladder. Weak modes like 'prefer'/'allow' will silently fall back to plaintext if the server declines TLS -- useless as a control. 'require' guarantees the session is encrypted but performs no certificate validation, so an attacker who can redirect the connection presents a self-signed certificate and reads everything: you get protection against passive sniffing only. 'verify-ca' validates the certificate chain against a CA bundle you supply, so a random self-signed certificate fails -- but with no hostname check, any certificate issued by that CA (another host in the same fleet, or a private CA an attacker can obtain a certificate from) impersonates the database. 'verify-full' adds the hostname/SAN match against the host in the connection string, which is what actually binds the identity. Production default is verify-full plus an explicitly distributed CA bundle. Common breakages: connecting by IP or through a CNAME that is not on the certificate, and poolers presenting their own certificate.
code
text · 5 linesmode encrypted? chain checked? hostname checked? stops MITM?
prefer maybe no no no
require yes no no no
verify-ca yes yes no partly
verify-full yes yes yes yesgo deeper
Know the ordering and that only the top mode checks the hostname; be able to say that encryption alone does not authenticate the server.
Explain what an attacker must do to beat each rung and name the concrete failure modes (missing CA bundle, IP in the connection string).
Cover fleet-wide rollout: bundle distribution, replica and pooler endpoints, expiry monitoring as an availability risk.
Set the standard (verify-full by default), define exception criteria and expiry, and decide who owns CA issuance and rotation.
## The ladder Every mainstream driver exposes roughly the same five-step ladder, with different spellings: 1. **disable** -- no TLS at all. 2. **allow / prefer** -- opportunistic. Try one, fall back to the other. The critical property is that *plaintext is an acceptable outcome*: a network attacker who answers 'I don't support TLS' gets a cleartext session. This is a performance/compatibility setting, not a security setting, and it is the default in several drivers. 3. **require** -- the session must be encrypted, but the server's certificate is not validated. Confidentiality against a passive eavesdropper; zero protection against an active one, because the attacker simply presents a self-signed certificate and the client accepts it. 4. **verify-ca** -- the certificate chain must validate to a CA in the client's trust store or supplied bundle. Self-signed junk is now rejected. What is still missing is the binding between *this certificate* and *the host I asked for*: any certificate issued by a trusted CA passes. If that CA is a public one, that is catastrophic; if it is your internal CA, then any other server in the fleet -- or anyone who can get a certificate issued -- can impersonate the database. 5. **verify-full** -- chain validation plus a check that the hostname in the connection string matches the certificate's subject alternative name. This is the mode that gives you the actual guarantee 'I am talking to the database I named'. ## Why the distinction is asked about so often Because 'the connection is encrypted' is the answer people give, and it is the wrong answer. The whole value of a public-key handshake is authenticating the peer; encryption without authentication protects you from the weakest attacker (a passive listener) and not from the realistic one (someone who can redirect traffic via DNS, ARP, a rogue route, a compromised service discovery entry, or a hijacked cloud endpoint). A checklist item that says 'TLS enabled' and a connection string that says sslmode=require are a common audit gap. ## Operational realities of verify-full - **You must distribute a CA bundle.** Managed cloud databases publish a CA certificate; the app image or secret store must ship it, and it must be updated before the provider rotates its root. - **The hostname you dial must be on the certificate.** Connecting by IP address, through an internal CNAME, or through a service mesh name typically fails verify-full even though everything is configured correctly. The fix is to dial the certified name, not to downgrade the mode. - **Failover and replicas.** Multi-host connection strings and read replicas each present their own certificate; every name in the list must be certified. - **Proxies and poolers.** A pooler terminates TLS and presents its own certificate, so the client verifies the pooler, not the database. That hop must be secured separately. - **Expiry is now an availability risk.** With verify-full, an expired or mis-rotated server certificate takes the application down rather than degrading silently. That is the correct trade -- but it means certificate expiry needs monitoring like any other production dependency. ## Reasoning about the choice Ask what an attacker must do to defeat each mode. Defeating 'require' takes only the ability to answer the connection -- a DNS or routing trick. Defeating 'verify-ca' takes one certificate from the trusted CA. Defeating 'verify-full' takes a certificate issued for the exact hostname, meaning either a CA compromise or control of your issuance process. Only the last is a real bar. The corollary: a mode below verify-full should be a documented, time-boxed exception during a migration, not a steady state.
- Your application fails to connect after switching from 'require' to 'verify-full'. What are the likely causes and what must you not do?Most often the client has no CA bundle for the server's issuer, or the host in the connection string (an IP address, an internal alias, or a pooler endpoint) is not listed on the certificate. Fix it by shipping the correct CA bundle and dialling the certified hostname. What you must not do is downgrade back to 'require' and call it done, since that removes the only check that stops impersonation.
- Is 'verify-ca' ever a defensible choice?Only when the certificate's subject cannot match the name you dial and you control issuance tightly -- for example a private CA that issues exclusively to that one database fleet, with short-lived certificates. Even then you are trusting that no other holder of a CA-issued certificate can be put in the path, so treat it as a temporary exception with a plan to reach verify-full.
saying these in an interview costs you the question
- Saying 'sslmode=require means the certificate is verified'
- Treating 'prefer' as a security setting when it silently accepts plaintext
- Downgrading to require or disabling verification to make a hostname mismatch go away
- Claiming verify-ca is equivalent to verify-full because both use a real CA
- Assuming the driver's default mode is safe