zitadel/zitadel · critical

cannot start DB client for queries: %w

Error message

cannot start DB client for queries: %w

What it means

startZitadel calls database.Connect to create the primary PGx pool for queries. If the connection to the configured PostgreSQL database cannot be established, the error is wrapped as 'cannot start DB client for queries'. ZITADEL cannot serve any traffic without this client, so startup aborts.

Source

Thrown at cmd/start/start.go:184

	Keys       *encryption.EncryptionKeys
	Eventstore *eventstore.Eventstore
	Queries    *query.Queries
	AuthzRepo  authz_repo.Repository
	Storage    static.Storage
	Commands   *command.Commands
	Router     *mux.Router
	TLSConfig  *tls.Config
	Shutdown   chan<- os.Signal
}

func startZitadel(ctx context.Context, config *Config, masterKey string, server chan<- *Server) error {
	showBasicInformation(config)

	i18n.MustLoadSupportedLanguagesFromDir()

	dbClient, err := database.Connect(config.Database, false)
	if err != nil {
		return fmt.Errorf("cannot start DB client for queries: %w", err)
	}
	new_domain.SetPool(v3_postgres.PGxPool(dbClient.Pool))

	keyStorage, err := cryptoDB.NewKeyStorage(dbClient, masterKey)
	if err != nil {
		return fmt.Errorf("cannot start key storage: %w", err)
	}
	keys, err := encryption.EnsureEncryptionKeys(ctx, config.EncryptionKeys, keyStorage)
	if err != nil {
		return err
	}
	q, err := queue.NewQueue(&queue.Config{
		Client: dbClient,
	})
	if err != nil {
		return err
	}

View on GitHub (pinned to 13948f2bcd)

Solutions

  1. Verify the wrapped error and test connectivity with psql using the exact connection parameters from your config
  2. Confirm Postgres is running and reachable (docker compose ps / kubectl get pods) and wait for readiness
  3. Check host, port, user, password, database, ssl_mode in config or ZITADEL_DATABASE_POSTGRES_* environment variables
  4. If Postgres starts slower than ZITADEL, add readiness gating/retries (e.g. depends_on: condition: service_healthy)

Example fix

// before
database:
  postgres:
    host: db
    port: 5433
// after
database:
  postgres:
    host: db
    port: 5432
Defensive patterns

Strategy: retry

Validate before calling

// before starting, probe the DB
nc, err := net.DialTimeout("tcp", net.JoinHostPort(host, port), 3*time.Second)
if err != nil { return fmt.Errorf("postgres unreachable: %w", err) }
nc.Close()

Try / catch

if err := waitForPostgres(cfg, 30*time.Second); err != nil {
    log.Fatalf("DB not reachable in time: %v", err)
}

Prevention

When it happens

Trigger: database.Connect(config.Database, false) fails: wrong host/port/user/password/database in config, TLS misconfiguration, DNS failure, or the Postgres server is unreachable.

Common situations: Postgres not yet ready in docker-compose/K8s (startup race), wrong ZITADEL_DATABASE_POSTGRES_* env vars, firewall/network policy blocking 5432, bad SSL mode or expired certificates.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


AI-assisted analysis of zitadel/zitadel@13948f2bcd (2026-09-06). Data as JSON: /api/errors/62a1012230cfef9d. Report an issue: GitHub.