BLE Troubleshooting: Connected but No Notifications (CCCD / Subscribe Fails)
A live GATT connection only means the link exists. Notifications and indications require a successful write to the Client Characteristic Configuration descriptor (CCCD)—and the peripheral must actually emit events on that characteristic.
1) What the CCCD does
For characteristics that support notify or indicate, the stack must enable them by writing 0x0001 (notify) or 0x0002 (indicate) to the CCCD handle. If this write fails or targets the wrong handle, you will see silence forever.
2) Discovery order and stale handles
- Re-discover after bonding: service/characteristic layout can change after encryption; cached handles go stale.
- Wrong characteristic instance: duplicated UUIDs require picking the correct handle under the right service.
- Subscribe after MTU/exchange (if required): some stacks expect a stable MTU before heavy GATT traffic.
3) Common subscribe errors
- Insufficient authentication: you must pair/bond before the CCCD write is permitted.
- Write not permitted: the descriptor or characteristic may be server-side gated.
- Application never enables server-side notify: the firmware might require a separate control write before streaming.
4) “Connected” but firmware never notifies
Some products only push data after a specific control command, a timer, or a sensor event. “Connected” is not “streaming.” Verify with the vendor app or documentation what event should trigger traffic.
5) Connection interval and throughput
Extremely long connection intervals or aggressive peripheral power saving can make notifications appear delayed or batched—test with a known-good sniffer or second client to compare.
Validation criteria
- CCCD write returns success and you can read back the expected value (where the stack allows).
- Subscribing on two different clients shows consistent behavior (rules out one buggy tool).
- You can explain silence as policy (no events) vs. misconfiguration (failed subscribe).