Problem: Redis does not support deleting keys by wildcard directly with DEL or UNLINK.

In this tutorial, we'll look at how to find and delete Redis keys matching a pattern, and why you should use SCAN instead of KEYS on production servers.

Sometimes you may need to purge a group of related Redis keys. For example, your application might store cached user data using keys such as:

cache:user:1001
cache:user:1002
cache:user:1003

and you want to remove everything matching:

cache:user:*

The obvious solution may look like this:

redis-cli KEYS "cache:user:*"

and then delete the returned keys.

There is a problem, though: using **KEYS** on a production Redis server can be dangerous.

Why you should avoid KEYS in production

The Redis KEYS command searches the entire keyspace in one operation.

For a small development database this may not matter. On a production Redis instance containing hundreds of thousands or millions of keys, however, scanning the entire keyspace at once can block Redis while the command is running.

Instead, Redis provides the cursor-based SCAN command, which incrementally iterates through the keyspace.

For example:

redis-cli --scan --pattern "cache:user:*"

This returns keys matching the pattern without performing one large blocking operation.

Before deleting anything, it is a good idea to run this command by itself and verify that the pattern matches only the keys you actually want to remove.

Delete keys matching a pattern using SCAN

Once you have verified the pattern, you can pipe the results to redis-cli:

redis-cli --scan --pattern "cache:user:*" |
    xargs -r redis-cli DEL

The process is simple:

  1. --scan iterates through the Redis keyspace using SCAN.
  2. --pattern limits the results to matching keys.
  3. xargs passes those keys to redis-cli DEL.
  4. Redis deletes the matching keys.

This is considerably safer than the old approach:

redis-cli KEYS "cache:user:*" | xargs redis-cli DEL

While you may still see this command in older tutorials and Stack Overflow answers, avoid using it against a busy production Redis instance.

There is another improvement we can make.

Redis provides the UNLINK command, which removes keys from the keyspace immediately but performs the actual memory reclamation asynchronously.

For large objects, this can reduce the amount of work performed synchronously by Redis.

The command becomes:

redis-cli --scan --pattern "cache:user:*" |
    xargs -r redis-cli UNLINK

For production cleanup jobs, SCAN combined with UNLINK is often a better choice than KEYS combined with DEL.

For small keys or development environments, DEL remains perfectly reasonable.

Working with a different Redis database

Redis uses database 0 by default.

If your keys are stored in another logical database, specify it using the -n option.

For example, to inspect matching keys in database 2:

redis-cli -n 2 --scan --pattern "cache:user:*"

And to delete them:

redis-cli -n 2 --scan --pattern "cache:user:*" |
    xargs -r redis-cli -n 2 UNLINK

Notice that the database is specified for both Redis connections.

Connecting to a remote Redis server

You can also specify the Redis host and port:

redis-cli -h redis.example.com -p 6379 \
    --scan --pattern "cache:user:*"

The same options need to be supplied to the deletion command:

redis-cli -h redis.example.com -p 6379 \
    --scan --pattern "cache:user:*" |
    xargs -r redis-cli -h redis.example.com -p 6379 UNLINK

If your Redis server requires authentication or TLS, configure redis-cli appropriately for your environment. Avoid putting passwords directly into shell commands or scripts where they may be exposed through shell history, process listings, logs, or source control.

Control the SCAN batch size

SCAN supports a COUNT option that provides Redis with a hint about how many elements to examine during each iteration.

With redis-cli, you can use:

redis-cli --scan --pattern "cache:user:*" --count 1000

A larger value can make the scan complete faster, but it also means more work during each iteration.

COUNT is a hint, not a guarantee that Redis will return exactly that many keys.

For most occasional maintenance tasks, the default behavior is fine. If you are cleaning a very large keyspace, experiment carefully rather than blindly setting a very large value.

Be careful with xargs and very large deletions

For a modest number of keys, piping the results through xargs is convenient:

redis-cli --scan --pattern "cache:user:*" |
    xargs -r redis-cli UNLINK

For very large production datasets, consider processing keys in controlled batches instead.

Deleting hundreds of thousands or millions of keys is operational work, not just a convenient one-liner. Even when SCAN and UNLINK are used, the operation consumes CPU, network bandwidth, memory-management resources, and replication bandwidth.

Run large cleanup operations during lower-traffic periods and monitor your Redis instance while they execute.

What about Redis Cluster?

Redis Cluster requires additional consideration.

Keys are distributed between multiple Redis nodes according to hash slots. A scan against one node does not necessarily represent the entire cluster keyspace.

If you need to remove matching keys across a Redis Cluster, make sure your cleanup process scans the appropriate primary nodes rather than assuming a single redis-cli --scan operation covers the entire cluster.

Also remember that multi-key commands in Redis Cluster are subject to hash-slot restrictions.

For large or important cluster cleanup operations, an application-level script using a Redis client library is generally preferable to a shell one-liner.

SCAN is not a snapshot

There is one more subtle detail worth knowing.

SCAN incrementally walks through a keyspace that may be changing while you scan it. It should therefore not be treated as a point-in-time snapshot of your Redis database.

For an occasional cache cleanup this normally isn't a problem. If your application is continuously creating keys matching the same pattern while your cleanup is running, however, you need to design the operation accordingly.

A safer workflow

When deleting Redis keys by pattern on a production system, I normally recommend doing it in two steps.

First, inspect what will be deleted:

redis-cli --scan --pattern "cache:user:*"

Check the output carefully.

Then perform the deletion:

redis-cli --scan --pattern "cache:user:*" |
    xargs -r redis-cli UNLINK

For another database:

redis-cli -n 2 --scan --pattern "cache:user:*" |
    xargs -r redis-cli -n 2 UNLINK

SCAN vs KEYS: quick comparison

CommandProduction useBehaviour
KEYS patternAvoid for keyspace iterationSearches the entire keyspace in one operation
SCANPreferredIncrementally iterates through the keyspace
DELFine for normal deletionRemoves keys and reclaims memory synchronously
UNLINKUseful for large valuesRemoves keys while reclaiming memory asynchronously

The important rule is simple:

Use **SCAN** to find matching keys on production Redis servers. Use **KEYS** primarily for debugging or small, controlled datasets.

And whenever you are deleting keys by wildcard, inspect the matches before piping them into DEL or UNLINK. One overly broad * can make your Redis cleanup much more exciting than intended.