Postgres on Google Cloud / Reference
Find the message. Read the layer. Apply the fix.
Layer 1 fails before the proxy works. Layer 2 fails after the proxy works. Layer 3 fails after you are connected. Several things below are not layers at all — they are network or credential-lifetime problems, and they are the ones people misdiagnose. Full explanation: lesson 4.
| Message | Layer | Fix |
|---|---|---|
403 … connectSettings |
1 | Identity lacks roles/cloudsql.client. Check group
membership. If the binding was just created, wait a minute —
IAM propagates. |
could not find default credentials |
— | Run gcloud auth application-default login. Note the
application-default part; plain gcloud auth login does
not write this credential. |
invalid_rapt / reauth required |
— | A reauthentication policy expired your ADC. It cannot be refreshed non-interactively — a human has to run the login at a terminal. |
Cloud SQL Admin API has not been used in project … |
— | Enable it:
gcloud services enable sqladmin.googleapis.com. |
instance does not exist / malformed name |
— | The URI is PROJECT_ID:REGION:INSTANCE_NAME — three parts, no
port, no hostname. |
address already in use |
— | Another proxy, or a local PostgreSQL, holds the port. Pick another and re-check which one your client is pointed at. |
| Message | Layer | Fix |
|---|---|---|
password authentication failed for user "you@example.com" |
2 | No IAM database user for that identity. Create it with the right
--type. |
password authentication failed for user "app@….iam.gserviceaccount.com" |
2 | Drop the .gserviceaccount.com suffix when
connecting. Full email when creating the user; truncated when connecting. |
| Connects, then asks for a password | — | --auto-iam-authn missing from the proxy command. |
pg_hba.conf rejects connection … no encryptionSSL is not enabled on the server |
— | Your client has SSL on. The hop to the proxy is plaintext loopback by design. Set SSL mode to disable. |
| Hangs, then times out — while 443 clearly works | — | Egress to the instance on port 3307 is blocked. The most commonly missed firewall rule in this whole subject. |
server closed the connection unexpectedly |
— | The proxy's credentials expired. It keeps listening, accepts the TCP connection, then drops it. Almost always a proxy left running overnight. Restart it; re-run the ADC login if it complains. |
| Worked yesterday, fails today, nothing changed | — | Same as above, nine times in ten. Check this before anything else. |
… IAM authentication is not enabled |
— | The instance flag cloudsql.iam_authentication is off. Turning
it on restarts the instance — schedule it. |
| Message | Layer | Fix |
|---|---|---|
permission denied for table … |
3 | Grants missing or stale. Typically a migration or restore created tables the last grant never covered. Re-run the grants script. |
permission denied for schema public on CREATE |
3 | Usually correct behaviour. Application roles hold no DDL. Run migrations as a dedicated DDL role — lesson 7. |
must be owner of table … |
3 | Same thing, for ALTER/DROP. Also correct. |
permission denied for sequence … on INSERT |
3 | Table privileges were granted, sequence USAGE was not. Grant
it, and add it to your default privileges. |
permission denied to set role |
3 | Not a member of that role. By design if the role is the object owner. |
permission denied for database … on connect |
3 | No CONNECT privilege on that database. Deliberate if someone
revoked it from PUBLIC. |
The dangerous category. Nothing errors.
| Symptom | Cause | Find it with |
|---|---|---|
current_user is not who you expect |
You are on a different proxy, or a shared password account | SELECT current_user, session_user; every session |
| The data is another environment's | Wrong credential for the config — a development key in a staging config, typically | SELECT current_database(); asserted at startup |
| One environment's principal can read another's data | Cluster-wide role membership. Roles are shared per instance, privileges are per database | The diagonal has_table_privilege query —
lesson 7 |
The application can DROP its own tables |
It owns them. Ownership grants DDL unconditionally and no revoke changes that | Check tableowner in pg_tables — every row
should name the owner role, never a login role |
| Symptom | Cause |
|---|---|
| Intermittent auth errors under load; most requests fine | A connector constructed per request. Build one per process at startup. |
| Auth fails reliably about an hour after deploy | A token fetched once by hand instead of letting the connector refresh it. |
KeyError / missing credential variable at boot |
Not running under the secrets injector, or pointed at the wrong config. |
| Works locally, fails on the server | Locally ADC is your login; on the server it is something else. Check which rung of lesson 6 is actually in play. |
| Worked, then stopped, nothing deployed | A key was deleted or the service account disabled. Check the audit log before creating a replacement key. |
gcloud auth application-default login.SELECT current_user, current_database(); — are you where you think?