The 10 Most Common BLE Bugs and How to Find Them

You’ve been debugging this BLE issue for three hours. You’ve restarted the phone, reflashed the firmware, and are now reading year-old forum posts where the accepted answer is “have you tried increasing the supervision timeout?” You’re starting to question whether Bluetooth was a good technology choice at all.
Here’s the thing: your bug is almost certainly one of about ten bugs. The same ten bugs that every firmware engineer hits, on every BLE project, every time. Recognizing the pattern is 70% of the fix. This article gives you the other 30%: the specific diagnostic method for each one, using tools that cost less than lunch for two.
Most of these bugs are firmware-side. A few are hardware masquerading as firmware. We’ll flag the difference. Let’s triage.
Your Debugging Toolkit (Before We Start)
You need three things. That’s it.
nRF52840 Dongle (~$10 USD) running the nRF Sniffer for Bluetooth LE plugin for Wireshark. This gives you passive over-the-air capture of advertising packets and connection events, decoded by Wireshark’s protocol dissectors. If you haven’t set this up yet, stop and do it now. It pays for itself on the first bug.
nRF Connect for Mobile (free, iOS/Android). Quick GATT exploration, connection testing, characteristic inspection. Your first sanity check for everything.
Structured firmware-side logging. Timestamped BLE event callbacks: connection events, disconnect reasons, GATT operations, parameter negotiations. This is the most underrated debugging tool in embedded development. If your logs don’t include disconnect reason codes, you’re flying blind.
This article deliberately avoids recommending $500+ protocol analyzers. The tools above cover 90%+ of what follows.
Bug #1: Connection Drops After a Few Seconds
Symptom: Device connects, exchanges a few packets, then disconnects. Your logs show reason code 0x08 (connection timeout) or 0x13 (remote user terminated connection).
Common cause: Your supervision timeout is too aggressive relative to your connection interval. If the supervision timeout is 1 second and your connection interval is 500ms, you only get two missed events before the link dies. Alternatively, your firmware is stalling in an interrupt handler or blocking call, causing the radio to miss its connection event window entirely.
Hardware flag: A noisy power supply causing radio brownouts during TX/RX looks identical to a firmware stall. If you see this on some boards but not others, measure your supply rail.
How to find it: First, check the disconnect reason code in your firmware logs. This tells you which side killed the connection. Then sniff with the nRF Sniffer: are packets actually being exchanged both ways, or does one side go silent before the disconnect? Finally, verify your math: supervision timeout should be at least 6× your connection interval.
Bug #2: Pairing Fails on Some Phones but Not Others
Symptom: Pairing works perfectly on a Samsung Galaxy. Fails every time on a Pixel. Or works on all Android devices but fails on iOS.
Common cause: Three usual suspects. First, mismatched I/O capabilities: your device declares DisplayYesNo but your firmware doesn’t actually handle the numeric comparison callback. Second, you’re enforcing MITM protection when the phone expects Just Works. Third (and most common in the field): stale bonding information. The phone has cached old encryption keys, but your device’s keys were erased by a reflash.
How to find it: Log the full pairing sequence: pairing request, pairing response, and key exchange events. Compare the I/O capability fields both sides declare. The fastest field test: delete the bond from both the phone’s Bluetooth settings and the device’s flash storage, then retry. If it works, you have a key management problem. Use nRF Connect to inspect the security properties of the connection after pairing.
Bug #3: MTU Negotiation Silently Fails
Symptom: You configured a 247-byte MTU. Your throughput is terrible. You’re getting 20-byte payloads.
Common cause: The MTU exchange was never initiated. Or it was initiated, but your firmware doesn’t handle the response callback, so your BLE stack quietly falls back to the default 23-byte MTU (20 bytes usable after ATT overhead). Many stacks require you to both request the exchange and process the response event. Miss either step and nothing errors out. It just doesn’t work.
How to find it: Add a log line in your MTU exchange callback. If it never fires, the exchange never happened. In Wireshark, filter for btatt.opcode == 0x02 (Exchange MTU Request). If it’s absent from the capture, your firmware isn’t initiating it. If the request is there but the response shows MTU 23, the remote side rejected your request.
Bug #4: Notifications Never Reach the Central
Symptom: Your peripheral firmware calls the send-notification function, gets a success return code, but the phone never receives data.
Common cause: The Client Characteristic Configuration Descriptor (CCCD) was never written by the central. This is the single most common GATT misunderstanding in BLE development: notifications are not enabled by default. The central must write 0x0001 to the CCCD handle. Your peripheral cannot do this on its own. It’s in the spec, and the spec means it.
Secondary cause: You’re queueing a notification before a previous GATT write operation has completed. The stack drops it silently.
How to find it: Log CCCD write events in your firmware. Open nRF Connect, connect to your device, and look at the characteristic. Does it show a “notify” button, or does it already show “Notifications enabled”? On-air, sniff the connection and look for the Handle Value Notification PDUs. If they’re absent, the CCCD wasn’t written. If they’re present, the problem is on the phone side.
Bug #5: Milliamps of Current Draw in “Sleep”
Symptom: Your battery life calculation assumed single-digit microamps in idle. Your multimeter shows 2–5 milliamps.
Common cause: Advertising interval set too short (20ms advertising burns power fast). GPIOs left floating or driving a load. A UART peripheral left enabled. A sensor still powered and polling. Or the BLE stack itself isn’t entering low-power mode because a software timer or pending event is keeping the system clock running.
Hardware flag: This is very often not a BLE bug at all. It’s a hardware/peripheral issue masquerading as one because “we added BLE and battery life tanked.”
How to find it: The definitive test: disable BLE entirely in your firmware and measure current. If it’s still high, BLE is innocent. Go check your peripherals and GPIOs. If current drops to expected levels, re-enable BLE features one at a time (advertising, connection, notifications) and measure after each. A Nordic Power Profiler Kit II (~$80) shows you current over time, making it easy to see exactly which event spikes your draw.
Bug #6: Advertising but Not Discoverable
Symptom: Your firmware logs say you’re advertising. Your phone’s scan shows nothing.
Common cause: You’re advertising on the wrong PHY. Extended advertising on Coded PHY won’t be seen by a phone doing legacy 1M PHY scans. Or your advertising data is malformed: a missing or incorrect AD Flags field (type 0x01) will cause some scanners to silently filter your device. Or your advertising interval is so long (multiple seconds) that the phone’s scan window simply misses you.
How to find it: Sniff the three advertising channels (37, 38, 39) with the nRF Sniffer. If you see your advertising PDUs in Wireshark, the radio is working, and the problem is in the PDU content or scanner settings. Inspect the decoded advertising data in Wireshark for structural errors. In nRF Connect mobile, enable “No filter” scan mode to rule out phone-side filtering.
Bug #7: Garbage Data in Characteristics
Symptom: Central reads a characteristic and gets byte-shifted values, stale data, or outright garbage.
Common cause: Endianness mismatch. The BLE specification mandates little-endian byte order for standard characteristics, but your firmware might be writing big-endian. Or (the insidious one): you passed a pointer to a local buffer to the BLE stack’s send function, and the buffer went out of scope or was overwritten before the stack actually transmitted it. Also check: does the characteristic length field in your GATT table match the actual number of bytes you’re writing?
How to find it: Log the raw hex bytes at the point your firmware hands them to the BLE stack. Capture the same PDU in Wireshark and compare byte-for-byte. Then compare to what nRF Connect shows. This three-point comparison tells you exactly where the corruption enters the chain.
Bug #8: Throughput Stuck at 5–10 kbps
Symptom: BLE 4.2+ supports 200+ kbps application throughput. You’re seeing 5–10 kbps and can’t figure out why.
Common cause: This is almost always a parameter problem, not a code problem. Check these four values: connection interval (if it’s 500ms, you’re sending data twice per second, and that’s your bottleneck), MTU (default 23 bytes means 20-byte payloads; see Bug #3), Data Length Extension (DLE) not enabled (capping you at 27-byte Link Layer payloads), and packets per connection event (some stacks default to one notification per event).
How to find it: Log the negotiated connection parameters. Then do the math: throughput = (payload_bytes × packets_per_event) / connection_interval. If the calculated throughput matches what you’re observing, the problem is parameter negotiation, not your data handling code. Fix the parameters, not the application.
Bug #9: iOS Rejects Your Connection Parameter Update
Symptom: Your peripheral requests a faster connection interval. Android accepts it. iOS rejects it with an L2CAP Connection Parameter Update Response of “rejected.”
Common cause: Apple has specific, published rules for acceptable connection parameters. The interval must be a multiple of 15ms. The minimum interval can’t be less than 15ms. The supervision timeout must be ≥ 6× the connection interval. Slave latency × connection interval can’t exceed 2 seconds. Violate any of these and iOS silently rejects the request.
How to find it: Log the L2CAP Connection Parameter Update Request and Response in your firmware. Compare your requested values against Apple’s Bluetooth Accessory Design Guidelines (search for “connection parameters” in that document). In Wireshark, the L2CAP parameter update exchange is clearly visible. Nine times out of ten, one parameter is slightly outside Apple’s allowed range.
Bug #10: Reconnection Fails After Bonding
Symptom: First pairing and connection works perfectly. Device reboots (or goes out of range and comes back), and the reconnection fails with “insufficient authentication” or encryption setup errors.
Common cause: Two primary culprits. First: bonding keys weren’t actually persisted to flash. Your pairing succeeded, keys were stored in RAM, device rebooted, keys are gone. Second: the phone is using a resolvable private address (RPA) that rotates every ~15 minutes, and your device’s stack isn’t using the peer’s Identity Resolving Key (IRK) to resolve it. Your device doesn’t recognize the reconnecting phone.
How to find it: On startup after a reboot, log whether bonding data is present in flash. If it’s empty, your persistence mechanism is broken. If keys are present, sniff the reconnection with Wireshark and look for the LL_ENC_REQ / LL_ENC_RSP exchange. You’ll see where the encryption setup fails. Check whether the phone’s address changed between the first connection and the reconnection attempt.
Quick-Reference Diagnostic Table
| Bug | Primary Symptom | First Check | Tool |
|---|---|---|---|
| #1 Connection drops | Disconnect after seconds | Disconnect reason code | Firmware logs |
| #2 Pairing fails on some phones | Phone-specific pairing failure | Delete bond on both sides | nRF Connect Mobile |
| #3 MTU silently fails | 20-byte payloads | MTU exchange callback | Wireshark |
| #4 Notifications not received | Central gets no data | CCCD write event | nRF Connect Mobile |
| #5 Excessive sleep current | mA instead of µA | Disable BLE, remeasure | Current profiler |
| #6 Not discoverable | Phone scan shows nothing | Advertising PDU structure | nRF Sniffer |
| #7 Data corruption | Garbage characteristic values | Raw hex at send point | Wireshark + logs |
| #8 Low throughput | 5–10 kbps | Negotiated connection params | Firmware logs |
| #9 Parameter update rejected | iOS rejects interval request | Apple’s parameter guidelines | Wireshark |
| #10 Reconnection fails | “Insufficient authentication” | Bond data persisted after reboot? | Firmware logs |
Build the Habit Before the Next Bug Hits
Every one of these bugs is a known bug. You are not the first person to hit it, and you won’t be the last. The difference between a three-hour debugging session and a thirty-minute one is whether you pattern-match first or probe randomly.
If you take one thing from this article: spend 30 minutes setting up the nRF52840 Dongle + Wireshark + nRF Sniffer pipeline before your next bug. Tape the dongle to your monitor. Have a Wireshark profile saved with BLE filters ready. The next issue will hit, and you’ll capture the answer in minutes instead of guessing for hours.
These ten bugs are the starting point. Each one has a deeper rabbit hole: connection parameter tuning, security mode tradeoffs, throughput optimization, power profiling methodology. That’s what the rest of the Advanced BLE Debugging series covers. But right now, you’ve got a checklist and a $10 dongle. That’s enough to find most of what’s broken.
Hubble Network connects BLE devices directly to satellite, eliminating the gateway and range constraints that cause half these headaches. See how it works →