A MariaDB too many connections error is a capacity-control event, not proof that max_connections is too low. The limit may be protecting the server from an application pool explosion, a retry storm, a connection leak, slow queries that hold sessions, or an outage that moved all traffic to fewer nodes. Raising it can convert clean connection rejection into memory exhaustion, CPU collapse, lock queues, or an OOM kill.
The visible client error can also be misleading. Error 1040 indicates the server's global simultaneous-connection limit, while per-account limits, blocked hosts, TCP backlog overflow, file descriptors, thread creation, proxy pools, authentication failures, and application-side pool timeouts have different evidence and remedies. A server with 150 connected sessions and two running queries needs a different fix from one with 150 active reports.
This guide provides a production incident runbook and a durable capacity design. It preserves administrative access, distinguishes rejection sources, inventories connections by account and host, finds active and idle pressure, stops retry amplification, changes limits only after a memory/concurrency check, configures per-account controls and an extra port, repairs pool behavior, and verifies service recovery without hiding the root cause.
Identify the exact failure first
Capture the complete client message, error number, SQLSTATE, timestamp, endpoint, server address, account, and whether failure occurred before or after authentication.
Common categories include:
Global connection exhaustion
ERROR 1040 (08004): Too many connections
The main listener has reached max_connections, apart from the reserved privileged slot.
Per-account simultaneous limit
The message states that a user has exceeded its max_user_connections resource. The global server may still have capacity.
Per-hour account resource limit
An account can also have MAX_CONNECTIONS_PER_HOUR. Repeated connect/disconnect churn can exhaust this even with low simultaneous use.
Host blocked after connection errors
MariaDB can block a host after too many successive failed handshakes under max_connect_errors. Raising max_connections does not unblock it.
Network or listener backlog failure
Clients may see timeout, reset, refusal, or “lost connection” rather than 1040. The process, socket, firewall, proxy, kernel backlog, or TLS/authentication path may be responsible.
Application pool exhaustion
The application times out waiting for its own pool even though MariaDB has free slots. Database status and application pool telemetry must be compared.
Do not collapse these into one alert. Exact errors make automated mitigation safer.
Understand MariaDB's connection limits
max_connections is the maximum simultaneous client connections on the main server interface:
SHOW GLOBAL VARIABLES LIKE 'max_connections';
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Max_used_connections';
MariaDB reserves one additional connection for an account with SUPER, or CONNECTION ADMIN on MariaDB 10.5.2+. This is intended for administration when ordinary slots are full.
The reserved slot is not magic:
- The privileged account still needs a working network/authentication path.
- Another privileged monitor or operator may already consume it.
- A saturated OS, blocked thread scheduler, or unavailable listener may prevent timely access.
- Broadly granting
CONNECTION ADMINweakens least privilege.
max_user_connections applies a global default per account where nonzero. An account-specific MAX_USER_CONNECTIONS resource can override that default. MariaDB accounts include both user and host, such as 'api'@'10.%'; resource tracking is per account definition rather than username text alone.
SHOW GLOBAL VARIABLES LIKE 'max_user_connections';
extra_port creates a separate administrative TCP listener with its own extra_max_connections. It uses one-thread-per-connection handling even when the main interface uses the thread pool.
Preserve and test emergency access before an incident
Create a least-privilege operational account through the organization's credential system. On MariaDB 10.5.2+, CONNECTION ADMIN permits bypassing connection limits and managing other connections without granting the full legacy SUPER privilege.
SHOW PRIVILEGES;
SHOW GRANTS FOR CURRENT_USER;
Do not copy a generic GRANT blindly. Diagnostic visibility, query cancellation, global variable changes, TLS requirements, source network, authentication plugin, and secret rotation should be designed separately.
Configure an extra port in a managed option file when justified:
[mariadb]
extra_port = 8385
extra_max_connections = 5
extra_port is non-dynamic and requires a planned restart. extra_max_connections is dynamic on supported releases. Secure the listener with bind address, firewall, TLS, and restricted source networks. Do not expose it publicly.
Test from the actual emergency location:
mariadb --host=db-admin.internal --port=8385
--user=db_incident --ssl-verify-server-cert
Use an option file or secure secret mechanism rather than a command-line password. Confirm the connection uses the intended port and identity:
SELECT CONNECTION_ID(), CURRENT_USER(), USER(), @@hostname, @@port;
Run the test during routine maintenance and after network/security changes. An untested reserved path is not an incident control.
Capture a low-impact capacity snapshot
Once connected, record server identity and settings:
SELECT VERSION(), @@version_comment, NOW(6), @@hostname, @@port;
SHOW GLOBAL VARIABLES WHERE Variable_name IN (
'max_connections',
'max_user_connections',
'extra_port',
'extra_max_connections',
'thread_handling',
'wait_timeout',
'interactive_timeout',
'back_log',
'thread_cache_size',
'open_files_limit',
'max_connect_errors'
);
Capture connection counters:
SHOW GLOBAL STATUS WHERE Variable_name IN (
'Threads_connected',
'Threads_running',
'Threads_created',
'Threads_cached',
'Connections',
'Max_used_connections',
'Aborted_connects',
'Aborted_clients',
'Connection_errors_max_connections',
'Connection_errors_internal',
'Connection_errors_peer_address',
'Connection_errors_select',
'Slow_launch_threads',
'Uptime'
);
Status availability varies. Connection_errors_max_connections is direct evidence of global-limit rejection. Use interval deltas because cumulative values persist since startup or reset.
Avoid FLUSH STATUS during an incident; it discards shared evidence.
Inventory current connections by account and source
Group the process list:
SELECT USER,
SUBSTRING_INDEX(HOST, ':', 1) AS client_host,
DB,
COMMAND,
COUNT(*) AS connections,
SUM(COMMAND <> 'Sleep') AS non_sleeping,
MAX(TIME) AS max_state_seconds
FROM information_schema.PROCESSLIST
GROUP BY USER, client_host, DB, COMMAND
ORDER BY connections DESC;
IPv6 host formatting and proxies can make SUBSTRING_INDEX insufficient. Use raw HOST where accuracy matters and correlate with connection attributes or proxy telemetry.
List oldest sessions:
SELECT ID,
USER,
HOST,
DB,
COMMAND,
TIME,
STATE,
LEFT(INFO, 500) AS sql_text
FROM information_schema.PROCESSLIST
ORDER BY TIME DESC
LIMIT 200;
Classify:
- Idle pooled connections (
Sleep). - Active CPU- or I/O-heavy queries.
- Lock waiters and blockers.
- Idle sessions with open transactions.
- Replication, event, backup, or admin threads.
- New sources or release versions.
Sleep does not prove safe termination. A sleeping connection can hold an uncommitted transaction and row/metadata locks. Join to information_schema.INNODB_TRX:
SELECT p.ID,
p.USER,
p.HOST,
p.COMMAND,
p.TIME,
t.trx_id,
t.trx_started,
t.trx_state,
t.trx_rows_locked,
t.trx_rows_modified
FROM information_schema.PROCESSLIST AS p
LEFT JOIN information_schema.INNODB_TRX AS t
ON t.trx_mysql_thread_id = p.ID
ORDER BY t.trx_started IS NULL, t.trx_started, p.TIME DESC;
Preserve process-list output securely because SQL and host details can be sensitive.
Calculate where the connections came from
Application pool capacity multiplies across instances:
potential_backend_connections
= application_instances * pool_max_per_instance
+ worker_and_job_pools
+ admin_and_monitoring
+ proxy_persistent_pools
+ replication_and_operations
+ failover_headroom
Example:
40 API pods * 20 connections = 800
10 workers * 10 connections = 100
proxy persistent pools = 100
operations and monitors = 20
potential total = 1020
If MariaDB is configured for 500, the application design can exceed it during normal scale-out. Conversely, configuring 1,200 does not prove the server can safely run 1,200 active queries.
Collect autoscaler changes, rollout overlap, old pods terminating slowly, failover routing, proxy pool state, and cron/batch start times. A rolling deploy can temporarily double pool populations.
Distinguish client pools from backend pools. A proxy may multiplex, pin transactions, or maintain persistent backend connections. Read its actual metrics and configuration.
Separate idle-slot pressure from active overload
Compare:
SHOW GLOBAL STATUS WHERE Variable_name IN
('Threads_connected','Threads_running','Max_used_connections');
Many connected, few running
Likely causes:
- Oversized or multiplied application pools.
- Long idle timeout.
- Leaked or abandoned connections.
- Proxy persistent pools.
- Prepared statements or open transactions keeping sessions.
The immediate risk is slots and memory. Reducing pool size and closing truly idle sessions may help without increasing query concurrency.
Many connected and many running
The server may be overloaded by slow/broad queries, lock waits, storage latency, or a traffic spike. Raising slots admits more work and can worsen queueing.
Investigate active digests, CPU, I/O, locks, temporary work, and application deadlines. Apply concurrency control before capacity expansion.
Connections churn rapidly
High Connections rate with moderate current count indicates clients do not pool, health checks reconnect too often, authentication fails/retries, or network devices break sessions. Fix lifecycle and transport rather than only increasing simultaneous slots.
Find the workload holding sessions
Capture current queries:
SELECT ID, USER, HOST, DB, TIME, STATE, LEFT(INFO, 1000) AS sql_text
FROM information_schema.PROCESSLIST
WHERE COMMAND <> 'Sleep'
ORDER BY TIME DESC;
Use Performance Schema digests where enabled:
SELECT SCHEMA_NAME,
DIGEST,
COUNT_STAR,
ROUND(SUM_TIMER_WAIT / 1000000000000, 3) AS total_seconds,
ROUND(AVG_TIMER_WAIT / 1000000000, 3) AS avg_ms,
SUM_ROWS_EXAMINED,
SUM_LOCK_TIME,
LEFT(DIGEST_TEXT, 500) AS digest_text
FROM performance_schema.events_statements_summary_by_digest
WHERE DIGEST IS NOT NULL
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 30;
Timer semantics and columns vary. Statement time includes waiting, not pure CPU. Correlate with lock waits, storage, and plans.
For recurring slow queries, use the slow log in a bounded capture. Fix predicates, indexes, N+1 patterns, transaction length, result sizes, and external calls within transactions. Faster completion returns connections to pools sooner.
Stop retry storms before changing server limits
When clients receive 1040, naive immediate retry creates more handshakes and load. A safe client policy uses:
- Bounded retries.
- Exponential backoff with jitter.
- One overall request deadline.
- Circuit breaking or admission control.
- No retry for invalid credentials or blocked accounts.
- Idempotency for operations that may have reached the server.
- Pool acquisition timeout shorter than request timeout.
Connection error does not always reveal whether a prior transaction committed. Retry business operations with idempotency keys rather than assuming nothing happened.
During an incident, reduce application replicas or pool limits carefully, pause optional workers and reports, and stop failing health checks from causing a reschedule cascade.
Do not configure probes that open a brand-new privileged database connection every second from every pod. Reuse or rate-limit health paths and distinguish readiness from liveness.
Free capacity with the least destructive action
Prefer application-side pool draining
Ask the offending service to stop creating new sessions and close idle ones cleanly. This preserves transaction semantics and prevents immediate reconnection.
Cancel one harmful statement
After verifying its connection ID and owner:
KILL QUERY 12345;
This cancels the current statement but leaves the connection. A client may retry immediately, and an open transaction may retain locks.
Close a confirmed leaked or idle connection
KILL CONNECTION 12345;
Closing rolls back an open transaction. A large rollback can consume I/O and time. Confirm INNODB_TRX, business operation, and owner first.
Generate reviewed kill statements instead of executing a mass kill
SELECT CONCAT('KILL CONNECTION ', ID, ';') AS proposed_action,
USER,
HOST,
TIME
FROM information_schema.PROCESSLIST
WHERE COMMAND = 'Sleep'
AND TIME > 3600
AND USER = 'report_app';
This only generates text for review. Do not pipe it directly back into MariaDB. Verify open transactions and pool retry behavior for every candidate.
Never kill replication, cluster, event, backup, or administrative threads based solely on age or username.
Decide whether a temporary max_connections increase is safe
The variable is dynamic:
SET GLOBAL max_connections = 600;
The number is illustrative. Before raising it, verify:
- Current and peak RSS/cgroup headroom.
- Per-session baseline and heavy-query workspace.
- Active versus idle ratio.
- CPU and storage saturation.
- File descriptor and systemd task limits.
- Thread handling model.
- Application retry and pool behavior.
- Failover capacity.
If the server is already CPU-bound with many running queries, more slots are likely harmful. If most sessions are idle, memory and connection lifecycle remain the primary risks.
Record the old value and a time-bounded rollback:
SELECT @@GLOBAL.max_connections;
Changing global value does not persist across restart unless option configuration is changed:
[mariadb]
max_connections = 600
Verify parsed options with mariadbd --print-defaults. Do not persist an emergency increase until load tests prove it.
MariaDB documentation notes that high connection values affect required file descriptors. On older systemd units, TasksMax could also cap threads; current MariaDB packages in specified maintenance releases remove that artificial cap. Inspect the actual service:
systemctl show mariadb
--property=TasksCurrent
--property=TasksMax
--property=LimitNOFILE
Do not raise OS limits without calculating memory and descriptors. A larger numeric ceiling is not capacity.
Apply per-account connection limits
Protect core traffic from one workload by setting account-specific simultaneous limits:
ALTER USER 'report_app'@'10.%'
WITH MAX_USER_CONNECTIONS 20;
Verify exact account resolution and resulting definition:
SHOW CREATE USER 'report_app'@'10.%';
SHOW GRANTS FOR 'report_app'@'10.%';
Twenty is an example. Set limits from the service pool budget plus rolling/failover behavior. A limit below legitimate deployment overlap can cause an outage.
Per-account resources include:
MAX_USER_CONNECTIONS: simultaneous connections.MAX_CONNECTIONS_PER_HOUR: new connection rate per hour.MAX_QUERIES_PER_HOURandMAX_UPDATES_PER_HOUR.MAX_STATEMENT_TIMEon supported versions.
Resource tracking is per 'user'@'host' account. Shared credentials combine all application instances under one account, which can be useful for a global cap but weakens attribution. Separate accounts by service and role without creating unmanageable credential sprawl.
Accounts with SUPER or CONNECTION ADMIN bypass relevant user limits. Do not grant those privileges to normal applications.
Tune idle session lifetime at the right layer
MariaDB closes non-interactive idle sessions after the session wait_timeout; interactive clients derive their initial value from interactive_timeout.
SELECT @@GLOBAL.wait_timeout,
@@SESSION.wait_timeout,
@@GLOBAL.interactive_timeout,
@@SESSION.interactive_timeout;
A lower global timeout can reclaim abandoned sessions:
SET GLOBAL wait_timeout = 600;
This becomes the default for new non-interactive sessions; existing sessions retain session values. Ten minutes is an example.
Do not use server timeout as the primary pool manager. If MariaDB closes a connection while the pool believes it is valid, the next borrower sees a broken socket and may retry. Configure pool max lifetime, idle timeout, validation, and keepalive coherently with proxies, firewalls, and server timeouts.
Open transactions should never idle until wait_timeout. Application code must commit or roll back promptly and clean connection state before returning it to the pool.
Fix application pool multiplication
A production pool configuration needs:
- Maximum size per process.
- Minimum idle size, often much smaller than maximum.
- Acquisition timeout.
- Idle and absolute lifetime.
- Validation strategy.
- Leak detection and stack attribution.
- Transaction cleanup on return.
- Backoff when database acquisition fails.
- Metrics for in-use, idle, pending, timeouts, and creation rate.
Budget globally:
sum(all normal service pools at maximum)
+ deploy overlap
+ batch/report pools
+ proxy backend pools
+ monitoring and operations
+ failover reserve
< safe MariaDB connection capacity
Do not set every service's pool maximum to MariaDB's max_connections. Autoscaling then multiplies the server limit by pod count.
Pool size should align with useful database concurrency, not request concurrency. Requests can queue briefly in the application where memory and deadlines are easier to control. An unbounded pool moves the queue into MariaDB and makes overload harder to shed.
Understand proxies and MaxScale pools
A database proxy can multiplex or pool backend sessions, but transactions, prepared statements, session variables, temporary tables, user variables, and connection state may pin a client to a backend.
Inspect:
- Frontend client connections.
- Backend connections per server.
- Persistent idle pool count.
- Queue depth and acquisition time.
- Transaction pinning.
- Failover redistribution.
- Monitor/admin connection use.
MariaDB MaxScale supports extra_port for backend monitoring and user-account retrieval. If extra_max_connections remains one, monitor and user-account management can contend for that slot; size and test according to the deployed MaxScale behavior.
A proxy does not create backend capacity. It can smooth bursts and reduce connection setup, but admitting more active statements still consumes CPU, memory, locks, and I/O.
Distinguish backlog and handshake problems
back_log controls pending TCP connection requests waiting for MariaDB to accept them, subject to operating-system limits. It is not the number of authenticated database sessions.
Inspect listener and sockets:
ss -lntp
ss -s
nstat 2>/dev/null | rg 'Listen|Retrans|Reset'
Check kernel listen limits:
sysctl net.core.somaxconn
sysctl net.ipv4.tcp_max_syn_backlog
Do not change these from a database article alone. Network queue sizing is host-wide and must be coordinated with security and platform engineering.
High Aborted_connects can mean authentication, TLS, handshake timeout, packet, DNS, or resource errors. Inspect MariaDB error logs and performance_schema.host_cache where available:
SELECT *
FROM performance_schema.host_cache
ORDER BY SUM_CONNECT_ERRORS DESC
LIMIT 30;
Describe the table first because columns vary. Do not solve failed credentials by increasing max_connect_errors indefinitely; fix the client and protect against abuse.
Evaluate thread handling and thread cache
With one-thread-per-connection, each client connection has a server thread. MariaDB's thread pool limits active workers across many clients and can reduce context switching in CPU-bound OLTP workloads with short queries.
SHOW GLOBAL VARIABLES LIKE 'thread_handling';
Enable thread pool only after production-like testing:
[mariadb]
thread_handling = pool-of-threads
It can queue simple queries behind work and does not reduce the number of logical sessions or fix leaks. Extra-port connections use one-thread-per-connection so administrators can bypass a stalled pool.
thread_cache_size caches threads for reuse after clients disconnect; it does not cap connections. MariaDB guidance treats it as a minor tuning variable on current releases, and it is unused under thread-pool handling. Do not set it to max_connections expecting protection.
High Threads_created relative to Connections can reveal connection churn, but repairing application pooling is usually more important than a larger thread cache.
Plan for failover and maintenance
Connection capacity must survive:
- One replica or cluster node unavailable.
- Rolling deployment with old and new app replicas overlapping.
- Database rolling restart and reconnection burst.
- Proxy failover or DNS convergence.
- Backup and maintenance connections.
- A traffic peak while one node recovers.
If three read replicas each operate at 60% of safe connection capacity, losing one sends remaining nodes toward 90% before retry overhead. Reserve explicit N-1 headroom or apply load shedding.
Stagger pool reconnect with jitter after a database restart. Thousands of clients reconnecting at once can exhaust backlog, authentication CPU, TLS handshakes, and connection slots even when steady-state pools fit.
Health checks should distinguish “server process reachable,” “accepting new traffic,” and “ready for full workload after recovery.”
Verify recovery and the lasting fix
During and after mitigation, compare:
| Evidence | Before | After |
|---|---|---|
| Error 1040 rate | Captured | Zero/expected |
Threads_connected |
Captured | Stable budget |
Threads_running |
Captured | Below concurrency knee |
| Connections created/sec | Captured | Expected pool behavior |
| Account/host distribution | Captured | No unexplained spike |
| App pool in-use/idle/pending | Captured | Healthy |
| CPU, memory, I/O, locks | Captured | Within headroom |
| Service P95/P99/errors | Captured | Recovered |
| Retry and circuit-breaker rate | Captured | Bounded |
| Replica/cluster health | Captured | Stable |
| Emergency admin path | Tested | Still available |
Load test steady state, burst, deploy overlap, one-node failure, database restart, slow-query degradation, and connection leak. A configuration that passes only normal traffic is incomplete.
After a temporary global increase, either persist a tested safe value or restore the original:
SET GLOBAL max_connections = 300;
Use the recorded value, not this example. Verify active pools do not immediately exceed the lower cap and remember existing connections are not evicted merely by lowering the limit.
Troubleshoot common failure patterns
Threads_connected is below max_connections but clients see 1040
Measurements may be from a different node, after the spike, or through a proxy. Check server identity, timestamp, per-account limits, reserved slot, and Connection_errors_max_connections deltas.
Increasing max_connections made latency worse
More active queries crossed the CPU, I/O, lock, or memory concurrency knee. Restore admission control, lower application pool concurrency, and fix slow work.
Most sessions are Sleep
Inspect application pool totals, wait timeout, proxy persistence, prepared statements, and open transactions. Close idle sessions through the owning pool rather than mass killing blindly.
Connections return immediately after KILL
The application or proxy is configured to maintain a minimum pool and reconnects. Stop or reconfigure the source, add backoff, and avoid fighting automation one connection at a time.
The reserved admin account cannot connect
The slot may be occupied, the account may lack the correct privilege, or network/authentication/OS saturation may be blocking it. Use a pretested secured extra port and out-of-band platform access.
One user hits a limit while others connect
Inspect the exact 'user'@'host' account and MAX_USER_CONNECTIONS, global max_user_connections, and CONNECTION ADMIN bypass. This is not global exhaustion.
Max_used_connections is near max but no incident occurred
It is a high-water mark since startup/reset, not current pressure. Pair it with timestamped monitoring, error counters, concurrency, and memory.
MariaDB cannot reach the configured high limit
Check memory, open files, systemd TasksMax, process/thread limits, kernel resources, and thread model. Do not keep increasing limits without reading service and kernel errors.
A host is blocked after bad handshakes
Fix credentials/TLS/network first. FLUSH HOSTS or host-cache action can unblock after cause removal, but indiscriminate flushing hides attack or misconfiguration evidence.
Monitoring and alert design
Monitor:
Threads_connectedas a fraction of safe capacity.Threads_runningand queue/service latency.Max_used_connectionswith event timestamps.Connection_errors_max_connectionsrate.- Connections created per second and aborted connects/clients.
- Connections by account, host, service, and database.
- Application pool in-use, idle, pending, acquisition timeout, and leaks.
- Proxy frontend/backend pools and pinning.
- CPU, RSS/cgroup headroom, storage latency, and locks.
- Retry, circuit breaker, and autoscaler behavior.
- Extra-port availability from a secure probe.
- N-1 failover capacity.
Alert before hard exhaustion. For example, sustained 80% slot use may be critical on a rapidly scaling fleet but harmless with idle pools and ample headroom. Combine percentage, growth rate, active ratio, errors, and service impact.
Avoid unbounded metric labels for raw host strings or SQL. Normalize service identity and retain sensitive detail in secure diagnostics.
Best practices checklist
- Capture the exact client error and server identity.
- Distinguish global, account, network, host-cache, and application pool limits.
- Maintain a least-privilege reserved admin path.
- Secure and test
extra_portbefore incidents. - Inventory sessions by account, host, command, and transaction.
- Compare connected with running sessions.
- Stop retry storms and optional workloads first.
- Prefer pool draining to mass KILL operations.
- Verify transaction state before closing a sleeping session.
- Raise
max_connectionsonly after memory and concurrency tests. - Budget pools across all application replicas and proxies.
- Use per-account limits to contain noisy workloads.
- Align pool idle lifetime with server and network timeouts.
- Reserve deploy, restart, and N-1 failover headroom.
- Verify recovery through errors, capacity, resources, and service latency.
FAQ
What causes MariaDB error 1040?
The main listener reached max_connections for ordinary accounts. One privileged reserved slot may remain, but per-account and network failures can produce different errors.
Can I increase max_connections without restarting MariaDB?
Yes, it is dynamic. The increase is not persistent unless configured, and it is unsafe without checking memory, active concurrency, file descriptors, thread limits, and workload.
Why are sleeping connections using all slots?
Application or proxy pools may retain idle sessions, leak them, or use long timeouts. Some sleeping sessions also hold open transactions, so verify before closing them.
What is MariaDB extra_port?
It is a separate TCP listener with its own connection quota for administration and monitoring. It uses one-thread-per-connection and requires startup configuration and network security.
Does thread pool increase max_connections?
No. It changes how active work is scheduled across threads. Logical client sessions still count toward connection limits and consume resources.
Should I lower wait_timeout?
Only in coordination with application and proxy pool lifetimes. It can reclaim abandoned idle sessions but may create broken pooled sockets and reconnect churn.
How many connections should each application pool have?
Size by useful database concurrency and total instances, including deploy overlap and failover. Do not give every process a maximum equal to the server limit.
Is it safe to kill all sleeping MariaDB sessions?
No. Some can hold open transactions or belong to critical services, and pools may reconnect immediately. Identify owner and transaction state, then drain through the source.
Conclusion
Fixing MariaDB too many connections safely means finding which capacity boundary failed and why. Preserve a tested administrative path, capture exact error counters, compare connected and running sessions, inventory account and host ownership, and identify application or proxy pool multiplication. During an incident, stop retry amplification and optional work before admitting more database concurrency.
max_connections is a guardrail, not a performance target. Set it from memory, CPU, storage, thread, and failover testing; keep per-account controls and application pool totals below that safe envelope. Align idle lifetimes, use bounded acquisition and retries, secure an extra port where appropriate, and verify N-1 and restart storms. The durable outcome is not merely making error 1040 disappear, but preserving predictable service when demand exceeds useful database concurrency.
Suggested Internal Links
- Configure MariaDB Connections and Thread Handling
- Troubleshoot MariaDB High Memory Usage and OOM Kills
- Troubleshoot MariaDB High CPU Usage Step by Step Safely
- Find and Fix MariaDB Lock Waits and Deadlocks Safely
- Use the MariaDB Slow Query Log for Better Diagnosis
- Secure a New MariaDB Server: Production Hardening Guide