﻿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
35685	Support for postgres connection pools and persistent connections	Tharinda Seth Wijesekera		"We are encountering issues with database connection pooling in Django when using psycopg3. The connections are being closed after each request, preventing effective pooling. Attempting to set CONN_MAX_AGE to a value greater than 0 results in an ImproperlyConfigured error, indicating that ""Pooling doesn't support persistent connections.""

Steps to Reproduce:

Configure Django to use psycopg3 with PostgreSQL.
Set CONN_MAX_AGE to a value greater than 0 in the DATABASES settings.
Observe that connections are closed after each request and pooling is not functioning as expected.
Expected Behavior:
Database connections should persist and be reused across requests according to the pooling configuration.

Actual Behavior:
Connections are closed after each request, and an error is raised when setting CONN_MAX_AGE to a non-zero value.

Configuration:

Python 3.10
Django 5.1
psycopg3 3.2.1 (with pooling enabled)
PostgreSQL


Config:

{{{
RDS_DB_ENGINE = ""django.db.backends.postgresql""

if USE_SSL and not TESTING:
    OPTIONS = {
        ""sslmode"": ""verify-full"",
        ""sslrootcert"": SECURE_RDS_CERTIFICATE_FILE,
        ""pool"": True
    }
else:
    OPTIONS = {
        ""sslmode"": ""disable"",
    }

DATABASES = {
    ""default"": {
        ""ENGINE"": IAM_DB_ENGINE if USE_RDS_IAM_AUTH else RDS_DB_ENGINE,
        ""NAME"": RDS_DB_NAME,
        ""USER"": RDS_DB_USER,
        ""PASSWORD"": RDS_DB_PASSWORD,
        ""HOST"": RDS_HOST,
        ""PORT"": RDS_PORT,
        ""OPTIONS"": OPTIONS,
    },
    ""read-db"": {
        ""ENGINE"": IAM_DB_ENGINE if USE_RDS_IAM_AUTH else RDS_DB_ENGINE,
        ""NAME"": RDS_DB_NAME,
        ""USER"": RDS_DB_USER,
        ""PASSWORD"": RDS_DB_PASSWORD,
        ""HOST"": RDS_READ_HOST,
        ""PORT"": RDS_READ_PORT,
        ""OPTIONS"": OPTIONS,
    },
}
}}}


Error and Pooling Logic: Django.db.backends.postgres.base


{{{
    @property
    def pool(self):
        pool_options = self.settings_dict[""OPTIONS""].get(""pool"")
        if self.alias == NO_DB_ALIAS or not pool_options:
            return None

        if self.alias not in self._connection_pools:
            if self.settings_dict.get(""CONN_MAX_AGE"", 0) != 0:
                raise ImproperlyConfigured(
                    ""Pooling doesn't support persistent connections.""
                )
            # Set the default options.
            if pool_options is True:
                pool_options = {}
}}}

Connection Close Logic:Django.db.backends.base.base



{{{
max_age = self.settings_dict[""CONN_MAX_AGE""]
self.close_at = None if max_age is None else time.monotonic() + max_age

def close_if_unusable_or_obsolete(self):
    if self.connection is not None:
        self.health_check_done = False
        if self.get_autocommit() != self.settings_dict[""AUTOCOMMIT""]:
            self.close()
            return

        if self.errors_occurred:
            if self.is_usable():
                self.errors_occurred = False
                self.health_check_done = True
            else:
                self.close()
                return

        if self.close_at is not None and time.monotonic() >= self.close_at:
            self.close()
            return

}}}

"	New feature	closed	Database layer (models, ORM)	5.1	Normal	wontfix		Tharinda Seth Wijesekera Florian Apolloner	Unreviewed	0	0	0	0	0	0
