InletDownload

Redis error BUSY

BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.

A Lua script or function has held the server for longer than busy-reply-threshold (5 seconds by default), so Redis answers almost everything else with BUSY. Stop it with SCRIPT KILL (FUNCTION KILL for a function); if it has already written, only SHUTDOWN NOSAVE stops it.

BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.

Tested on Redis 8.10.2 and Valkey 8.1.10 (temporary servers) · Updated 9 October 2026

What it means

A Lua script (EVAL, EVALSHA) or a function (FCALL) runs atomically: while it runs, Redis does nothing else. Other clients’ commands wait. Once the script has run for longer than busy-reply-threshold (5,000 ms by default; its old name, lua-time-limit, still works), Redis starts answering them, but only to say it’s busy:

BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.

For a function the wording names FUNCTION KILL instead, and a long module command gives BUSY Redis is busy running a module command. The script itself keeps running. Nothing you send runs until it ends or is stopped; even PING, GET and INFO got BUSY in the test below.

Stopping it depends on what it has done:

  • It hasn’t written anything yet: SCRIPT KILL (or FUNCTION KILL) stops it. The client that ran it gets an error and nothing changes, because the script made no changes.
  • It has already written: stopping it halfway would break the promise that a script runs completely or not at all, so Redis refuses with UNKILLABLE. Your choices are to wait for it to finish or to stop the whole server with SHUTDOWN NOSAVE, which doesn’t save, so the script’s half-done work isn’t persisted. Anything written since your last save or AOF write is lost too.

Common causes

  1. A loop that doesn’t end: a bug in a while condition, or a retry loop inside the script.
  2. A script that does too much at once: walking a big set or hash, deleting thousands of keys, or calling KEYS inside the script on a large database.
  3. Data that grew. A script that took 50 ms on a small key takes seconds once the key holds millions of elements.
  4. A function (FCALL) with any of the above.

A slow ordinary command, such as KEYS * on a big database, also holds up the server, but clients wait for it rather than getting BUSY.

How to fix it

Stop the script

From another connection (yours is waiting on the script, or is another client):

redis-cli SCRIPT KILL       # for EVAL / EVALSHA
redis-cli FUNCTION KILL     # for FCALL

The BUSY message tells you which one: it names SCRIPT KILL for a script and FUNCTION KILL for a function. SCRIPT KILL while a function is running gets the same BUSY reply; when nothing is running you get NOTBUSY No scripts in execution right now.

If you get UNKILLABLE

UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in a hard way using the SHUTDOWN NOSAVE command.

If the script will finish, waiting is the safe choice. If it never will, SHUTDOWN NOSAVE and start the server again: it comes back with what was last saved. On a replicated setup, check which server becomes primary afterwards.

Find the script

The server log names it:

# Slow script detected: still in execution after 5000 milliseconds. You can try killing the script using the SCRIPT KILL command. Script name is: 694a5fe1ddb97a4c6a1bf299d9537c7d3d0f84e7.

For EVALSHA, that’s the SHA1 your application sends; search your code for the script, or compare with the SHA1 that SCRIPT LOAD returns for each candidate.

Make scripts short, and killable for longer

  • Do bounded work per call: process a batch of, say, 1,000 elements and return a cursor, and let the application call again. Iterate with SCAN/HSCAN/SSCAN from the application, not KEYS in the script.
  • Do the reading and computing first and the writes last. Until its first write, a script can be killed.
  • Mark scripts that only read with #!lua flags=no-writes (or use EVAL_RO), so they can always be killed.

Don’t raise the threshold to hide it

A higher busy-reply-threshold doesn’t make the script faster: clients wait longer before being told the server is busy. 0 turns the BUSY replies off altogether, so clients wait for as long as the script runs. On AWS ElastiCache lua-time-limit is fixed at 5,000 ms, and when a script exceeds it ElastiCache sends SCRIPT KILL and, if that fails, restarts the node, AWS’s docs say.

Reproduce it

Only on a temporary Redis 8.10.2 container, because a looping script blocks the whole server:

docker run --rm -d --name seo-redis-busy redis:8 redis-server
redis-cli CONFIG GET busy-reply-threshold     # "5000"
redis-cli EVAL "while true do end" 0          # in one terminal
redis-cli PING                                # in another, 2 seconds later

The PING waited about 3 seconds, until the script had run for 5, then got:

(error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.

GET greeting and INFO server got the same. SCRIPT KILL returned OK, and the EVAL that had been running returned:

(error) ERR Script killed by user with SCRIPT KILL... script: 694a5fe1ddb97a4c6a1bf299d9537c7d3d0f84e7, on @user_script:1.

A function that loops, loaded with FUNCTION LOAD and run with FCALL spin 0:

(error) BUSY Redis is busy running a script. You can only call FUNCTION KILL or SHUTDOWN NOSAVE.

SCRIPT KILL got that same reply; FUNCTION KILL returned OK.

A script that writes first, then loops (redis.call("SET","seo:busy","1") while true do end): PING got BUSY as before, and SCRIPT KILL got:

(error) UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in a hard way using the SHUTDOWN NOSAVE command.

SHUTDOWN NOSAVE stopped the server (and with it the temporary container).

Valkey 8.1.10 names itself in the message: BUSY Valkey is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE. Its UNKILLABLE text was the same as Redis’s.

In Inlet

In a query tab, Stop also kills a long script that the tab is running. The server’s rule still applies: a script that has already written can’t be killed by anyone. When another client’s script holds the server, Inlet shows the BUSY message and links it to this page.

Related

Sources