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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions