﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
37500	Include the database alias in connection-failure error messages	Abdul Qoyyuum		"= Description =

When a project configures more than one entry in `DATABASES`, a failed
connection raises `django.db.utils.OperationalError` whose message comes
straight from the database driver and only mentions host and port:

{{{
django.db.utils.OperationalError: connection failed: connection to server
    at ""127.0.0.1"", port 5432 failed: Connection refused
}}}

Nothing in the exception identifies ''which'' database alias failed
(`default` vs any other entry in `DATABASES`), nor the configured `NAME`,
`USER`, or `HOST` for that alias. In a multi-database setup the same
host:port may be correct for one alias and wrong for another, so the reader
cannot tell which connection string was actually attempted. This is
especially painful when host/credentials come from environment variables —
a stale or overridden `*_HOST` can silently point `default` at localhost
while a second alias points at a remote server, and the error gives no hint
which of the two failed.

== Reproduction ==

{{{#!python
DATABASES = {
    ""default"": {
        ""ENGINE"": ""django.db.backends.postgresql"",
        ""NAME"": ""app"",
        ""USER"": ""app"",
        ""HOST"": ""localhost"",   # nothing listening here
        ""PORT"": 5432,
    },
    ""ecomdb"": {
        ""ENGINE"": ""django.db.backends.postgresql"",
        ""NAME"": ""etx_ecom"",
        ""USER"": ""report_api"",
        ""HOST"": ""192.168.80.72"",
        ""PORT"": 5432,
    },
}

User.objects.get_by_natural_key(""alice"")        # uses 'default'
EcomRecords.objects.using(""ecomdb"").exists()    # uses 'ecomdb'
}}}

Whichever connection fails, the raised message has the same shape; the only
way to know which alias was involved is to read the traceback back to the
call site and cross-check `connections[alias].settings_dict` manually.

= Proposal =

Enrich the error as it propagates out of
`BaseDatabaseWrapper.ensure_connection()` / `connect()` /
`get_new_connection()` so the driver error is reported together with the
connection alias and the key settings for that alias, e.g.:

{{{
django.db.utils.OperationalError: could not connect to database 'ecomdb'
    (postgresql 'etx_ecom' at 192.168.80.72:5432 as 'report_api'):
    connection failed: connection to server at ""127.0.0.1"",
    port 5432 failed: Connection refused
}}}

An alternative or complementary approach is to attach the context
programmatically instead of only in the message text — e.g.
`BaseException.add_note()` (Python 3.11+) or an attribute such as
`exc.django_connection_alias = self.alias` — so that logging,
error-reporting tools, and tests can pick the alias up without parsing the
message.

= Notes =

 * `django.db.backends.signals.connection_created` exists for ''successful''
   connections, but there is no equivalent signal or hook on failure. Today
   the only way to add the alias is to subclass each backend's
   `DatabaseWrapper` under a custom `ENGINE` path — which also means the
   workaround must be re-implemented per third-party backend rather than once
   in Django itself.
 * Care should be taken not to include the connection `PASSWORD` in the
   enriched message; `NAME`/`USER`/`HOST`/`PORT` are already visible in
   `settings_dict` and match what drivers print today.
"	Cleanup/optimization	new	Database layer (models, ORM)	6.1	Low		databases, error messages, multiple databases		Unreviewed	0	0	0	0	0	0
