redis/redis-py · error · ConnectionError
No connection available.
Error message
No connection available.
What it means
Raised as ConnectionError('No connection available.') by BlockingConnectionPool.get_connection when the underlying Queue.get(block=True, timeout=self.timeout) raises Empty — i.e. no connection became available within the configured timeout. BlockingConnectionPool uses a bounded queue and waits up to self.timeout seconds before giving up; unlike the default pool it does not error immediately at the cap, but it does error if nothing frees up in time.
Solutions
- Increase max_connections or self.timeout to match expected hold times.
- Fix connection leaks — always return connections; prefer the high-level Redis client which manages release for you.
- Cap concurrency (thread/async pool size) to stay within the Redis pool size.
- Shorten or remove long-running blocking commands, or dedicate a separate pool/client for pubsub and blocking calls.
Example fix
# before pool = BlockingConnectionPool(max_connections=10, timeout=2) # raises under load # after pool = BlockingConnectionPool(max_connections=50, timeout=20)
Defensive patterns
Strategy: retry
Validate before calling
# Pre-check: ensure expected concurrency <= pool size before relying on the pool.
if expected_concurrent_ops > pool.max_connections:
raise RuntimeError(f'Concurrency {expected_concurrent_ops} exceeds pool size {pool.max_connections}; raise max_connections or reduce fan-out') Try / catch
import time
from redis.exceptions import ConnectionError
for attempt in range(4):
try:
return r.get('key')
except ConnectionError as e:
if 'No connection available' in str(e) and attempt < 3:
time.sleep(0.2 * (2 ** attempt))
continue
raise # raise so the caller can shed load or alert Prevention
- Tune max_connections and timeout to match worst-case hold times.
- Fix connection leaks; let the high-level client manage release.
- Bound your concurrency (thread/async pools) within the Redis pool size.
- Move long-running blocking commands and pubsub to a dedicated pool.
When it happens
Trigger: All max_connections of a BlockingConnectionPool are checked out longer than self.timeout (default DEFAULT_TIMEOUT=20s). Connection leaks, long-running blocking commands, or saturated pubsub listeners holding all slots.
Common situations: Blocking commands (BLPOP, BRPOP, WAIT, MONITOR) tying up every connection. Thread/async fan-out exceeding pool size. Leaked connections never released. timeout set too low for the workload.
Related errors
- Too many connections
- Maintenance notifications are not supported with
- "max_connections" must be a positive integer
- No connection available.
- Argument 'db' must be 0 or None in cluster mode
AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10).
Data as JSON: /api/errors/eaeb78b65952bc96.
Report an issue: GitHub.
Appendix: source
Thrown at redis/connection.py:3714
"""
start_time_acquired = time.monotonic()
# Make sure we haven't changed process.
self._checkpid()
is_created = False
# Try and get a connection from the pool. If one isn't available within
# self.timeout then raise a ``ConnectionError``.
connection = None
try:
if self._in_maintenance:
self._lock.acquire()
self._locked = True
try:
connection = self.pool.get(block=True, timeout=self.timeout)
except Empty:
# Note that this is not caught by the redis client and will be
# raised unless handled by application code. If you want never to
raise ConnectionError("No connection available.")
# If the ``connection`` is actually ``None`` then that's a cue to make
# a new connection to add to the pool.
if connection is None:
# Start timing for observability
start_time_created = time.monotonic()
connection = self.make_connection()
is_created = True
finally:
if self._locked:
try:
self._lock.release()
except Exception:
pass
self._locked = False
# Record state transition: IDLE -> USED
# (make_connection already recorded IDLE +1 for new connections)View on GitHub (pinned to 6a6b581b48)