</>CodeWithKarani

Redis 'Connection refused' in Frappe: Find the Real Cause, Not Just Restart

Karani GeoffreyKarani Geoffrey7 min read

You run bench migrate or bench update, and instead of doing its job it throws a Redis connection error naming a port you have never configured. The number in the error looks suspicious, so you go hunting for where that port is set, find nothing obvious, and start trying random fixes. bench restart. Reboot. Reinstall Redis. Sometimes one of them works, and you never learn why.

Here is the thing to internalise before you touch anything: that port is supposed to be there, and it is not a fixed number. Frappe assigns Redis ports per bench and writes them into your site config. The error is not telling you the port is wrong. It is telling you nothing is listening on the port Frappe expects. Those are very different problems, and only one of them is fixed by restarting.

This is the most common Frappe setup error I see, and almost every forum answer stops at "just restart". Let me show you how to find the actual cause in about five minutes instead.

The port in the error is read from sites/common_site_config.json, not hardcoded, so do not chase it. Find the real ports there, confirm whether Redis is actually listening with redis-cli -p <port> ping, and check whether the process is running. If you use supervisor, check supervisorctl status; on a manual dev bench, Redis must be started by bench start; in Docker, the cause is almost always a container/network alias mismatch, not a dead process.

The exact error

redis.exceptions.ConnectionError: Error 111 connecting to localhost:13000. Connection refused.

Port 13000 is the Frappe default for the redis_cache instance. You may also see 11000, which is the default for redis_queue. "Error 111" is just the Linux ECONNREFUSED errno surfacing through Python: the kernel actively rejected the connection because nothing is bound to that port on that host. It is not a timeout and not a DNS failure. Something should be listening there and is not.

Why the port looks wrong but is not

When you create a bench, Frappe picks Redis ports and writes them into sites/common_site_config.json. Every Frappe process, the web workers, the background workers, the scheduler, reads its Redis URLs from that file. So the "13000" in the traceback is simply whatever that file says. Changing it by hand almost always makes things worse, because now the config and the running Redis disagree in a new way.

The real cause is one of a small set of things:

  • The Redis process that should own that port is not running (most common on servers managed by supervisor after an update).
  • On a manual dev bench, you ran bench migrate in one terminal without bench start running in another, so nothing ever started Redis.
  • In Docker, the config points at localhost but Redis lives in a separate container reachable only by its service name, so localhost refuses the connection.
  • A firewall or hardened kernel is blocking loopback connections (rare, but it happens on locked-down VPS images).

Notice that "restart" only fixes the first one, and only sometimes. That is why blind restarting is a coin flip.

Error 111 connecting to localhost:PORT read the real port from common_site_config.json redis-cli -p PORT ping ==> PONG? no yes (PONG) Redis not listening: find why it is down Redis is up: it's a config/host mismatch manual bench: run bench start supervisor: supervisorctl status docker: fix service name, not localhost
One question splits the whole problem: does the port answer PONG or not. Everything downstream follows from that.

The fix, step by step

Step 1: Read the real ports from your config

Stop guessing what the ports are. From your bench directory, print them:

cd ~/frappe-bench
cat sites/common_site_config.json

You are looking for the three Redis URLs:

{
 "redis_cache": "redis://localhost:13000",
 "redis_queue": "redis://localhost:11000",
 "redis_socketio": "redis://localhost:13000"
}

The port in your traceback must match one of these. If it does not, you are running a command against a different bench or a stale config, which is itself the bug. The matching Redis config files live under config/redis_cache.conf and config/redis_queue.conf in the same bench.

Step 2: Ask that port directly if Redis is alive

This one command replaces a dozen guesses. Point redis-cli at the exact port from Step 1:

redis-cli -p 13000 ping

If Redis is running you get:

PONG

If you instead get Could not connect to Redis at 127.0.0.1:13000: Connection refused, you have confirmed the real problem: nothing is listening. That is a very different situation from a config mistake, and it tells you which branch to take next. Run the same check against the queue port (redis-cli -p 11000 ping) because the two instances fail independently.

Step 3a: Manual dev bench, start it properly

On a development bench, Redis is not a background service. It is started by bench start, which launches the web server, workers, scheduler and the Redis instances together via the Procfile. If you opened one terminal and ran bench migrate without bench start running in another, Redis was never up. The fix is simply to run bench start in its own terminal and keep it running, then run your command in a second terminal.

Step 3b: Production with supervisor, check the processes

A production bench runs Redis under supervisor. After a bench update or a reboot, one of the Redis programs can fail to come up. Look at the actual status rather than assuming:

sudo supervisorctl status
frappe-bench-redis:frappe-bench-redis-cache      RUNNING   pid 812, uptime 0:04:11
frappe-bench-redis:frappe-bench-redis-queue      FATAL     Exited too quickly
frappe-bench-redis:frappe-bench-redis-socketio   RUNNING   pid 814, uptime 0:04:11

A FATAL or repeatedly restarting Redis is your answer. Read its log to see why it will not start:

sudo supervisorctl tail -1000 frappe-bench-redis:frappe-bench-redis-queue stderr

Common causes are a stale dump.rdb it cannot load, a permissions problem on the bench directory, or two benches fighting over the same port. Fix the reported cause, then sudo supervisorctl restart all. If the supervisor config itself is out of date after an update, regenerate it with bench setup supervisor and reread it, a common miss after upgrades that also trips up the Frappe scheduler.

Step 3c: Docker, stop pointing at localhost

In a Docker deployment this error usually means your config says redis://localhost:13000 but Redis runs in a separate container. Inside the app container, localhost is the app container itself, where no Redis lives, so the connection is refused. The Redis host must be the Redis service name from your compose file, for example redis-cache, not localhost. Frappe's official Docker images set these via environment so containers resolve each other by service name on the shared network. If you hand-edited a config to localhost, that is the bug; point it back at the service name and make sure both containers share a network.

Verifying the fix

Two checks confirm you are genuinely fixed, not temporarily lucky. First, every Redis port answers:

redis-cli -p 13000 ping && redis-cli -p 11000 ping
PONG
PONG

Then run the command that originally failed:

bench --site your-site.local migrate

It should proceed past the point where it previously threw Error 111. If you fixed it under supervisor, confirm nothing is in FATAL anymore with sudo supervisorctl status. A related Redis-import failure with a different signature is covered in the No Module Named redis.commands writeup, which is a Python package problem, not a connection one, worth ruling out if ping already returns PONG.

What people get wrong

"Change the port in the config to something else." The port is not the problem; nothing listening on it is. Editing common_site_config.json to a different port just moves the target so that now nothing listens there either, and you have added a mismatch between the config and the running Redis conf files.

"Just bench restart and hope." On a manual dev bench there is nothing to restart; you needed bench start. In Docker there is no dead process to restart; you have a host misconfiguration. Restart only helps the supervisor case, and even then only if the process was crashed rather than mis-configured. Diagnose first with redis-cli ping, then act.

"Reinstall Redis." Reinstalling the Redis package does nothing for a bench whose supervisor entry is FATAL because of a bad dump.rdb, and nothing for a Docker host mismatch. You will spend twenty minutes and end up exactly where you started.

When it is still broken

  • PONG works but Frappe still refuses. Confirm the command is running against the same bench whose common_site_config.json you read. Multiple benches on one box each have their own ports; running a command from the wrong directory targets the wrong config.
  • Loopback is firewalled. On a hardened VPS, check that connections to 127.0.0.1 on the Redis ports are allowed. Redis binding and reachability on loopback is a genuine (if rare) cause; test with redis-cli -h 127.0.0.1 -p 13000 ping.
  • Two benches share a port. If you cloned a bench or copied a config, two instances may claim 13000. Give one a distinct set of ports and regenerate its supervisor and Redis config.
  • Redis is OOM-killed on a small VPS. On a 1GB box under load Redis can be killed by the kernel, showing up as an intermittent refusal. Check dmesg | grep -i oom; if so, the real fix is more memory or a lower maxmemory, related to the tradeoffs in Redis OOM command not allowed.

The discipline is one line long: read the real port, then ask that port if it is alive. Every correct fix for this error branches off that single answer, and no amount of restarting substitutes for knowing it.

Frequently asked questions

Why does Frappe say Error 111 connecting to localhost:13000?
Port 13000 is the Frappe default for the redis_cache instance, read from sites/common_site_config.json rather than hardcoded. Error 111 is the Linux ECONNREFUSED errno, meaning nothing is listening on that port. It is not a wrong port; the Redis process that should own it is not running or, in Docker, is in another container.
Where are the Frappe Redis ports actually configured?
In sites/common_site_config.json as the redis_cache, redis_queue and redis_socketio URLs, with matching config files under config/redis_cache.conf and config/redis_queue.conf in the same bench. The defaults are 13000 for cache and 11000 for queue, but they are assigned per bench, so do not assume a fixed number.
How do I check whether Frappe's Redis is actually running?
Run redis-cli -p 13000 ping (and redis-cli -p 11000 ping for the queue) using the exact ports from common_site_config.json. PONG means Redis is up and the problem is config or host mismatch; Connection refused confirms nothing is listening, so you need bench start on a dev bench or supervisorctl status on a production one.
Why does the Redis error happen only in Docker?
In Docker, a config pointing at redis://localhost:13000 resolves localhost to the app container itself, where no Redis runs, so the connection is refused. The Redis host must be the Redis service name from your compose file (for example redis-cache), and both containers must share a network so they resolve each other by name.
#Frappe#Redis#bench#Supervisor#Docker
Keep reading

Related articles