What this usually means
The root cause is almost never a Redis server bug. Typically it's one of: a channel name mismatch (including case or trailing spaces), the subscriber connecting to a different Redis instance or database, the subscriber losing connection and not resubscribing, or the publisher using a different mechanism (e.g., Redis Streams vs Pub/Sub). Pub/Sub is 'fire and forget'—if the subscriber isn't actively subscribed at the exact moment the message is published, the message is lost. This is the most common point of confusion with other messaging systems like RabbitMQ or Kafka.
The first ten minutes — establish facts before touching code.
- 1Run `redis-cli PSUBSCRIBE *` on the subscriber host to see all messages on all channels—if messages appear, it's a channel pattern match issue.
- 2Check subscriber's client list: `redis-cli CLIENT LIST` and look for the subscriber connection. Ensure it shows 'flags=O' (monitor) or 'flags=S' (subscriber).
- 3Verify publisher and subscriber use the same Redis instance: `redis-cli INFO server | grep redis_version` on both ends.
- 4Test with a blocking subscribe in a separate terminal: `redis-cli SUBSCRIBE mychannel` and publish from another terminal. Confirm the subscriber receives the message.
- 5Inspect subscriber logs for reconnection events. Many client libraries log 'reconnecting' or 'connection lost' at INFO/WARN level.
- 6Check for network partitions: `ping` the Redis server from the subscriber host and look for packet loss or latency spikes.
The specific files, logs, configs, and dashboards that usually own this bug.
- searchSubscriber application logs for reconnection or subscription error messages
- searchRedis server log (usually /var/log/redis/redis-server.log) for client disconnections
- searchRedis MONITOR output: `redis-cli MONITOR` to see all commands including PUBLISH
- searchPublisher application code: verify it's calling PUBLISH (not other Redis commands)
- searchChannel name strings in both publisher and subscriber—check for hidden characters or encoding mismatches
- searchConfiguration files for Redis database selection (select 0 vs select 1) and connection strings
- searchNetwork monitoring dashboards for latency or packet loss between publisher and subscriber hosts
Practical causes, not theory. These are the things you will actually find.
- warningChannel name mismatch: trailing spaces, different case, or Unicode normalization differences
- warningSubscriber connected to a different Redis database (SELECT index) than publisher
- warningSubscriber client lost connection and reconnected without resubscribing to channels
- warningPublisher using Redis Streams (XADD) while subscriber expects Pub/Sub (SUBSCRIBE)
- warningNetwork partition or load balancer dropping idle connections without subscriber noticing
- warningClient library bug: some async clients have race conditions on subscription setup
Concrete fix directions. Pick the one that matches your root cause.
- buildUse PSUBSCRIBE with a pattern that matches both publisher and subscriber channels (e.g., PSUBSCRIBE prefix:*)
- buildAdd automatic resubscription logic on reconnect: listen for 'connection ready' events and re-issue SUBSCRIBE commands
- buildSwitch to Redis Streams for reliable delivery if message persistence is needed
- buildNormalize channel names: trim whitespace, lowercase both sides, use a shared constant or config
- buildSet TCP keepalive on Redis client connections to detect stale connections faster
- buildUse a heartbeat message pattern: publisher sends periodic 'ping' messages on a monitoring channel to verify subscriber liveness
A fix you cannot prove is a guess. Close the loop.
- verifiedRun `redis-cli PUBSUB CHANNELS '*'` to list all active channels—the expected channel must appear when subscriber is connected
- verifiedUse `redis-cli PUBSUB NUMSUB mychannel` to see subscriber count—should be >0
- verifiedTest end-to-end with a script that publishes a unique message and checks subscriber receives it within a timeout
- verifiedMonitor network: `tcpdump -i any port 6379` on subscriber host to confirm PUBLISH commands arrive
- verifiedCheck client library health: most libraries expose a 'isConnected' or 'isSubscribed' flag
- verifiedAfter fix, stress-test with rapid publish/subscribe cycles to ensure no race conditions
Things that make this bug worse or harder to find.
- warningDon't assume PUBLISH returning 1 means subscribers got the message—it only means server received it
- warningDon't use Redis Pub/Sub for mission-critical message delivery—it has no persistence or delivery guarantees
- warningDon't forget that Pub/Sub messages are not queued; if subscriber is slow, messages are dropped
- warningDon't mix database numbers: PUBLISH and SUBSCRIBE must be on the same logical database
- warningDon't rely on 'blocking' subscribers without timeout handling—they may hang forever
- warningDon't ignore client library version: some older versions have known subscription bugs
The Silent Subscriber: Messages Lost After Deployment
Timeline
- 14:00Deploy new version of notification service to production
- 14:15Users report not receiving real-time notifications
- 14:20Check subscriber logs: no errors, but no messages processed
- 14:25Publisher shows messages being sent: PUBLISH returns 1
- 14:30Run PUBSUB CHANNELS: expected channel missing
- 14:32Discover subscriber is subscribed to 'notifications' but publisher sends to 'notification' (typo)
- 14:34Fix channel name in publisher configuration
- 14:36Notifications resume immediately
At 14:00, I deployed a new version of our notification service that sends real-time updates via Redis Pub/Sub. Within 15 minutes, users started complaining about missing notifications. The subscriber logs showed no activity—no errors, no messages processed. The publisher logs confirmed messages were being sent: PUBLISH returned 1 every time. At first, I suspected a network issue or Redis server overload.
I ran `redis-cli PUBSUB CHANNELS '*'` and the expected channel 'notifications' was missing. I checked the subscriber's subscription list and saw it was subscribed to 'notifications'—but the publisher code had a typo: it was publishing to 'notification' (missing the 's'). The publisher's configuration had been changed in the new deployment from a shared constant to a hardcoded string, and someone dropped the 's'.
I corrected the publisher's channel name to 'notifications', redeployed, and notifications started flowing within seconds. The lesson: always centralize channel names in a config file or constant, and add a startup check that verifies the subscription is active. We also added a monitoring alert that fires if PUBSUB NUMSUB for 'notifications' drops to zero.
Root cause
Publisher channel name typo: 'notification' vs subscriber channel 'notifications'.
The fix
Changed publisher channel to 'notifications' (consistent with subscriber).
The lesson
Centralize channel names and add monitoring for subscriber count.
Many engineers assume PUBLISH returning 1 means at least one subscriber received the message. That's wrong. PUBLISH returns the number of subscribers that were subscribed at the moment the message was published. However, this count is the number of subscriber connections matching the channel pattern—it does not guarantee the message was delivered to the application. The message could be lost if the subscriber's socket buffer is full (client slow) or if the subscriber disconnects between the PUBLISH and the actual push.
To verify delivery, you need to instrument your subscriber to log received messages or use MONITOR to see the actual PUBLISH command and subsequent push. But MONITOR is expensive in production. A better approach: have the subscriber publish an acknowledgment on a separate channel, and have the publisher wait for that ack with a timeout.
Redis connections are TCP connections. If a network blip occurs, the TCP connection may drop without the client noticing for a while (TCP timeout can be minutes). Many client libraries have automatic reconnection, but they often do not automatically resubscribe to channels. This is a common pitfall: the subscriber appears connected but is not subscribed to any channels.
Check your client library documentation for a 'reconnection callback' or 'connection ready' event. In the callback, you must re-issue all SUBSCRIBE commands. Some libraries like redis-py have a 'connection_error' callback; others like node-redis have a 'reconnecting' event. Always test reconnection by killing the Redis server and restarting it while the subscriber is running.
Redis Pub/Sub is a simple messaging pattern with no persistence: if a subscriber is not listening, the message is gone forever. It is suitable for low-latency, non-critical broadcasts. If you need guaranteed delivery, message replay, or consumer groups, use Redis Streams. Streams persist messages in memory (or disk with RDB/AOF) and support acknowledgments.
Some teams start with Pub/Sub and later hit reliability issues. The fix is to migrate to Streams. However, the API is different: XADD to publish, XREAD to consume. There's no direct migration path; you need to change both publisher and subscriber code. Plan this early if your use case requires delivery guarantees.
When all else fails, use MONITOR to see every command processed by Redis. Run `redis-cli MONITOR` on the server. Then publish a test message. Look for the PUBLISH command. If you see it, the server received it. Then look for the 'publish' event sent to subscribers (appears as a push, not a command). In MONITOR output, you won't see the push directly; you'll see the PUBLISH and then the subscriber's commands (if any). To see the push, you need to sniff the TCP traffic.
CLIENT LIST is essential: it shows all connections, their flags (S for subscriber, O for monitor), and idle time. If a subscriber connection has flags= (none), it means it's a normal connection, not subscribed. Check idle time to see if the connection is stuck.
Frequently asked questions
Why does PUBLISH return 1 but my subscriber still doesn't get the message?
PUBLISH returns the number of subscriber sockets that matched the channel at the time of publication. However, the message may be lost if the subscriber's receive buffer is full (client slow) or if the subscriber disconnects immediately after. Also, the subscriber might be subscribed to a different database (SELECT index). Use PUBSUB CHANNELS to verify the channel exists and PUBSUB NUMSUB to confirm subscriber count.
Does Redis Pub/Sub guarantee message delivery?
No. Redis Pub/Sub is 'fire and forget'. If a subscriber is not connected at the exact moment a message is published, the message is lost. There is no queue, no persistence, no retry. For guaranteed delivery, use Redis Streams or a message broker like RabbitMQ.
My subscriber reconnects after a network failure but stops receiving messages. Why?
Most Redis client libraries automatically reconnect the TCP connection but do not automatically resubscribe to channels. After reconnection, the subscriber is connected but not subscribed. You must implement a reconnection callback that re-issues SUBSCRIBE commands for all channels.
Can I use Redis Pub/Sub across different databases (e.g., select 0 and select 1)?
No. Pub/Sub channels are scoped to the database number. A subscriber on database 0 will not receive messages published on database 1. Ensure both publisher and subscriber use the same database (usually database 0).
What is the difference between SUBSCRIBE and PSUBSCRIBE?
SUBSCRIBE subscribes to exact channel names (e.g., 'news'). PSUBSCRIBE subscribes to channel patterns (e.g., 'news:*' matches 'news:sports', 'news:weather'). Messages published to a channel matching the pattern are received. However, patterns are more CPU-intensive and should be used sparingly.