Celery Error 111 Connection refused (tested)

Celery raises kombu.exceptions.OperationalError: Error 111 ... Connection refused when delay() cannot reach the broker. Either Redis/RabbitMQ is not running at that address, or Celery is using its default amqp://localhost:5672 broker because your setting was not read.

1. Reproduce it: delay() with the broker down

import time
from celery import Celery
app = Celery('tasks', broker='redis://localhost:6379/0')
@app.task
def add(x, y):
    return x + y
t = time.monotonic()
try:
    add.delay(2, 3)
except Exception as e:
    print(f'{type(e).__module__}.{type(e).__name__}: {e}')
print(f'after {time.monotonic() - t:.1f}s')

Output:

kombu.exceptions.OperationalError: Error 111 connecting to localhost:6379. Connection refused.
after 0.9s

No Redis is listening on localhost:6379, so delay() retries the publish and then raises kombu.exceptions.OperationalError: Error 111 connecting to localhost:6379. Connection refused. Errno 111 is the OS-level ECONNREFUSED: the host answered, but nothing accepts connections on that port. The task never reaches a worker.

2. Fail fast instead of retrying

import time
from celery import Celery
app = Celery('tasks', broker='redis://localhost:6379/0')
@app.task
def add(x, y):
    return x + y
t = time.monotonic()
try:
    add.apply_async((2, 3), retry_policy={'max_retries': 1, 'interval_start': 0})
except Exception as e:
    print(f'{type(e).__name__}: {e}')
print(f'after {time.monotonic() - t:.1f}s')

Output:

OperationalError: Error 111 connecting to localhost:6379. Connection refused.
after 0.1s

retry_policy on apply_async() controls the publish retries (here 0.9 s by default, 0.1 s with one retry and no wait). Catch kombu.exceptions.OperationalError around delay() in a web view if a broker outage should not turn into a 500 for the user.

3. "[Errno 111]" on port 5672: Celery is not reading your broker setting

from celery import Celery
class settings:                       # stands in for Django settings
    BROKER_URL = 'redis://localhost:6379/0'          # wrong name for namespace='CELERY'
app = Celery('proj')
app.config_from_object(settings, namespace='CELERY')
print('broker used:', app.connection_for_write().as_uri())
@app.task
def add(x, y):
    return x + y
try:
    add.apply_async((2, 3), retry_policy={'max_retries': 0})
except Exception as e:
    print(f'{type(e).__name__}: {e}')
class settings:
    CELERY_BROKER_URL = 'redis://localhost:6379/0'   # matches the namespace
app2 = Celery('proj')
app2.config_from_object(settings, namespace='CELERY')
print('broker used:', app2.connection_for_write().as_uri())

Output:

broker used: amqp://guest:**@localhost:5672//
OperationalError: [Errno 111] Connection refused
broker used: redis://localhost:6379/0

If the error mentions amqp://guest@localhost:5672 even though you use Redis, Celery fell back to its default RabbitMQ broker because your setting was never read. With app.config_from_object('django.conf:settings', namespace='CELERY'), every setting needs the CELERY_ prefix: CELERY_BROKER_URL, not BROKER_URL. Print app.connection_for_write().as_uri() to see which broker the app actually uses.

4. Checklist

Related: Redis connection refused, Python ConnectionRefusedError Errno 111.

Frequently asked questions

What does Celery Error 111 Connection refused mean?

The broker (Redis or RabbitMQ) is not accepting connections at the configured host and port, so delay() cannot publish the task.

Why does Celery connect to amqp://localhost:5672 when I use Redis?

Your broker setting was not read, e.g. BROKER_URL instead of CELERY_BROKER_URL with namespace='CELERY', so Celery uses its default RabbitMQ URL.

Written with AI assistance. Measured on 2026-10-23 with Celery 5.6.3, kombu 5.6.2 and Python 3.14.7 (python:3-alpine in Docker, no broker running). Each block was run verbatim and the output pasted unedited. PlainHeaders is our extension; Python and Celery are free.