Skip to content

Aurora SSL + URL-Encoded Password Fix

Problem

After migrating to encrypted Aurora Serverless v2, the API Lambda (Node.js/Hono) returned {"status":"unhealthy","checks":{"database":"disconnected"}} while the migrator Lambda (Python/psycopg2) connected fine.

Symptoms

  • Health endpoint: 503 with database: disconnected
  • Plate lookup: 500
  • API docs (no DB): 200 OK
  • Migrator Lambda: connects and runs migrations successfully
  • Same DATABASE_URL, same VPC, same security group

Root Cause

Two issues combined:

1. Unencoded Password in DATABASE_URL

SST generates random passwords for Aurora clusters. These passwords can contain characters like :, #, ?, ) that break URL parsing. The Node.js pg library parses the connection string as a URL, causing the password to be truncated at the first special character.

Example: postgresql://postgres::#tT4...?:pI)@host:5432/reggie

  • Python's psycopg2 handles this (more tolerant URL parser)
  • Node.js pg does not (standard URL parser, # starts fragment, ? starts query)

2. SSL Required but Not Configured Correctly

Encrypted Aurora clusters require SSL connections. The pg_hba.conf entry rejects non-SSL connections with: no pg_hba.conf entry for host ... no encryption.

The fix: ssl: { rejectUnauthorized: false } in the pg Pool config (RDS CA certs not in Node.js trust store).

Solution

URL-Encode Password in sst.config.ts

const encodedPassword = $resolve([db.password]).apply(([pw]) =>
  encodeURIComponent(pw),
);
const databaseUrl = $interpolate`postgresql://${db.username}:${encodedPassword}@${writerHost}:${db.port}/${db.database}`;

SSL in services/api-ts/src/db/index.ts

...(env.ENVIRONMENT !== "development" && {
  ssl: { rejectUnauthorized: false },
}),

Prevention

  • Always URL-encode passwords in database connection strings
  • Test database connectivity after any infrastructure change (not just migration success)
  • The smoke test (scripts/smoke-test.sh) checks /health which validates DB connectivity
  • SST issue: python.container wraps Dockerfiles, breaking pip install
  • CI builds migrator Docker image directly to work around this