Skip to content

PostgreSQL connection leak: idle connections accumulate and exhaust max_connections (0.7.2) #109

Description

@guipratiko

Welcome!

  • Yes, I have searched for similar issues on GitHub and found none.

What did you do?

Running Evolution GO 0.7.2 with PostgreSQL 17 (Docker) and a small number of WhatsApp instances (4–5 created, ~4 connected at the same time).

Setup:

  • PostgreSQL 17.10 (Debian, Docker container)
  • Default max_connections = 100
  • Evolution GO connected to database evogo_auth (whatsmeow tables)
  • Multiple instances active, handling normal message traffic

Steps:

  1. Deploy Evolution GO 0.7.2 and connect 4 WhatsApp instances
  2. Let the service run under normal load (messages, contacts, webhooks)
  3. Monitor PostgreSQL with pg_stat_activity
  4. Optionally delete/disconnect instances and observe connection count

Monitoring queries used:

SELECT count(*) FILTER (WHERE client_addr = '<evolution_go_ip>') AS evolution_go,
       count(*) AS total
FROM pg_stat_activity;

SELECT pid, datname, client_addr, state, LEFT(query, 100)
FROM pg_stat_activity
WHERE client_addr = '<evolution_go_ip>';

### What did you expect?

- Evolution GO should maintain a **reasonable, bounded connection pool** per instance
- Idle connections should be **released** when instances are deleted/disconnected
- Total DB connections should scale roughly linearly with active instances (e.g. ~24 per instance), not grow unbounded
- The service should **not** exhaust PostgreSQL `max_connections` with only a handful of instances
What did you ob

### What did you observe instead of what you expected?

With only **4 connected instances**, Evolution GO opened **1216+ idle connections** to PostgreSQL (`evogo_auth`), all from the same container IP. Over time, connections kept increasing even after deleting most instances.

Eventually PostgreSQL logged: FATAL: sorry, too many clients already


When the limit was hit, Evolution GO entered a **retry loop** (~every 2 seconds), making the situation worse. Instances became unstable and required restarting both PostgreSQL and Evolution GO.

**Example `pg_stat_activity` (healthy-looking period before crash):**
- `evolution_go`: 16 connections
- `total`: 24 / 100
- Most connections: `state = idle`
- Last queries included:
  - `INSERT INTO whatsmeow_message_secrets (...)`
  - `SELECT first_name, full_name, push_name, business_name, redacted_phone FROM ...`
  - `SELECT version, compat FROM whatsmeow_version LIMIT 1`

**After deleting instances:** connection count did **not** drop proportionally — suggesting a **connection leak**.

**Workaround:** Downgrading to **0.7.1** on the same infrastructure:
- Only **3 idle connections** total (2`auth`, 1`users`)
- New container IP, databases split as `onlydbevoflow_auth` + `onlydbevoflow_users`
- No `too many clients` errors under the same workload

This suggests a **regression in 0.7.2** around DB connection lifecycle / pool management.

### Screenshots/Videos

_No response_

### Which version are you using?

0.7.2 (issue); workaround verified on 0.7.1


### What is your environment?

Docker

### If applicable, paste the log output

**PostgreSQL — connection limit reached:**
2026-07-10 12:37:15.989 UTC [277] FATAL: sorry, too many clients already 2026-07-10 12:37:42.693 UTC [280] FATAL: sorry, too many clients already ... 2026-07-10 15:17:28.880 UTC [985] FATAL: sorry, too many clients already 2026-07-10 15:18:41.730 UTC [1030] FATAL: sorry, too many clients already (retry storm: dozens of FATAL errors every ~2 seconds between 15:1715:20 UTC)

**PostgreSQL — startup (normal):**
PostgreSQL Database directory appears to contain a database; Skipping initialization LOG: database system is ready to accept connections

**Heavy checkpoint activity before/during incident (possible symptom of high write load):**
checkpoint complete: wrote 3166 buffers (19.3%); write=269.127 s; distance=33948 kB checkpoint complete: wrote 3865 buffers (23.6%); write=269.907 s; distance=38841 kB

**Connection stats (0.7.2, before crash):**
evolution_go | total | limite 16 | 25 | 100

**Connection stats (0.7.1, same workload after downgrade):**
datname | client_addr | state | qtd onlydbevoflow_auth | 10.11.63.135 | idle | 2 onlydbevoflow_users | 10.11.63.135 | idle | 1

### Additional Notes

**Suspected root cause:** Connection pool not releasing idle connections on instance disconnect/delete; possible leak per instance or per goroutine in 0.7.2.

**Impact:** Production outage — all DB clients rejected once `max_connections` is hit; Evolution GO retry loop accelerates exhaustion.

**Suggested investigation:**
- Compare `database/sql` pool settings (`SetMaxOpenConns`, `SetMaxIdleConns`, `SetConnMaxLifetime`) between 0.7.1 and 0.7.2
- Ensure `Close()` / pool cleanup runs on instance delete and disconnect
- Add connection pool metrics or logging for observability

**Mitigations we applied:**
- Increased `max_connections` to 1000
- Downgraded to 0.7.1 (resolved the issue)
- `idle_session_timeout` on PostgreSQL (preventive)

Happy to provide more logs or test a patched 0.7.2 build.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions