@@ -76,6 +76,7 @@ import (
7676"github.com/coder/coder/v2/coderd/database/dbmetrics"
7777"github.com/coder/coder/v2/coderd/database/dbpurge"
7878"github.com/coder/coder/v2/coderd/database/migrations"
79+ "github.com/coder/coder/v2/coderd/database/pgfileurl"
7980"github.com/coder/coder/v2/coderd/database/pubsub"
8081"github.com/coder/coder/v2/coderd/devtunnel"
8182"github.com/coder/coder/v2/coderd/entitlements"
@@ -433,18 +434,29 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd.
433434}
434435config := r .createConfig ()
435436
436- // If a postgres URL file is specified, read the URL from the file.
437+ // If a postgres URL file is specified, register a driver that
438+ // re-reads the file on each connection attempt. This supports
439+ // credential rotation without restarting the server.
437440if vals .PostgresURLFile != "" {
438441if vals .PostgresURL != "" {
439- return xerrors .Errorf ("cannot specify both --postgres-url and --postgres-url-file" )
442+ return xerrors .Errorf ("cannot specify both --postgres-url and --postgres-url-file flags " )
440443}
444+ // Read the URL once for initial validation and migrations.
445+ logger .Debug (ctx ,"database connection URL sourced from file" )
441446postgresURL ,err := ReadPostgresURLFromFile (vals .PostgresURLFile .String ())
442447if err != nil {
443448return err
444449}
445450if err := vals .PostgresURL .Set (postgresURL );err != nil {
446- return xerrors .Errorf ("setpostgres URL from file: %w" ,err )
451+ return xerrors .Errorf ("setdatabase URL from file: %w" ,err )
447452}
453+ // Register a driver that re-reads the file on each new connection.
454+ sqlDriver ,err = pgfileurl .Register (sqlDriver ,vals .PostgresURLFile .String (),logger )
455+ if err != nil {
456+ return xerrors .Errorf ("register database file URL driver: %w" ,err )
457+ }
458+ }else if vals .PostgresURL != "" {
459+ logger .Debug (ctx ,"database connection URL sourced from environment variable" )
448460}
449461
450462builtinPostgres := false
@@ -2845,6 +2857,47 @@ func ReadPostgresURLFromFile(filePath string) (string, error) {
28452857return strings .TrimSpace (string (content )),nil
28462858}
28472859
2860+ // PostgresParams holds parameters for resolving a postgres connection.
2861+ type PostgresParams struct {
2862+ // URL is the direct connection URL (from --postgres-url or CODER_PG_CONNECTION_URL).
2863+ URL string
2864+ // URLFile is the path to a file containing the connection URL
2865+ // (from --postgres-url-file or CODER_PG_CONNECTION_URL_FILE).
2866+ URLFile string
2867+ // Auth is the authentication method (e.g., "password" or "awsiamrds").
2868+ Auth string
2869+ }
2870+
2871+ // ResolvePostgresParams resolves the postgres connection URL and SQL driver.
2872+ // It handles mutual exclusion between URL and URLFile, reads the URL from file
2873+ // if specified, and registers the appropriate SQL driver based on the auth type.
2874+ // Returns the driver name and the resolved URL.
2875+ func ResolvePostgresParams (ctx context.Context ,params PostgresParams ,baseDriver string ) (driver string ,dbURL string ,err error ) {
2876+ dbURL = params .URL
2877+
2878+ // Handle mutual exclusion and file reading.
2879+ if params .URLFile != "" {
2880+ if params .URL != "" {
2881+ return "" ,"" ,xerrors .Errorf ("cannot specify both --postgres-url and --postgres-url-file" )
2882+ }
2883+ dbURL ,err = ReadPostgresURLFromFile (params .URLFile )
2884+ if err != nil {
2885+ return "" ,"" ,err
2886+ }
2887+ }
2888+
2889+ // Register the appropriate driver.
2890+ driver = baseDriver
2891+ if codersdk .PostgresAuth (params .Auth )== codersdk .PostgresAuthAWSIAMRDS {
2892+ driver ,err = awsiamrds .Register (ctx ,driver )
2893+ if err != nil {
2894+ return "" ,"" ,xerrors .Errorf ("register aws rds iam auth: %w" ,err )
2895+ }
2896+ }
2897+
2898+ return driver ,dbURL ,nil
2899+ }
2900+
28482901func getAndMigratePostgresDB (ctx context.Context ,logger slog.Logger ,postgresURL string ,auth codersdk.PostgresAuth ,sqlDriver string ) (* sql.DB ,string ,error ) {
28492902dbURL ,err := escapePostgresURLUserInfo (postgresURL )
28502903if err != nil {