All posts

Blog

HC-05 disconnects after a few seconds? It is resetting, not disconnecting

Troniction

A steady connection that collapses and restarts, over and over

It pairs. The phone says connected. You get maybe three seconds — sometimes long enough to send one character — and then it is gone. Reconnect and the same thing happens again, often after almost exactly the same few seconds.

It is probably not disconnecting. It is resetting. When the supply dips below what the module needs to run, the module reboots. From the phone's side that is indistinguishable from the module walking away: the connection drops, there is no error, and nothing anywhere says brown-out. The single most useful thing you can do is give the module its own power for two minutes, with its ground tied to the Arduino's, and see whether it holds.

There are four causes worth knowing, and the first one is not the one you would guess.

Why "it paired, so the power is fine" is backwards

This is the reasoning that sends people off to debug their sketch, and it is exactly inverted.

Pairing is the hungriest thing the module ever does:

What the module is doingWhat it draws
Pairing or being discoveredunder 40 mA
Actually sending dataabout 20 mA
Paired and idleunder 8 mA

So a module that paired successfully has already survived its worst moment, once. That is the whole of what it proves. It does not prove the rail can hold — and a rail that is marginal rather than inadequate behaves exactly this way: fine at the peak when everything else is quiet, and gone the moment anything else asks for current.

This is what makes the symptom different from a module that never appears in the phone's list at all. That one usually fails at the 40 mA peak and never gets past it. This one clears the peak and then dies in the calm afterwards, which feels like the opposite problem and is the same shortage seen from the other side.

The sixty-second test

Before changing anything, run the one test that splits the causes in half.

Power the module from something other than the Arduino, and tie the grounds together.

  1. Feed the module's VCC from a separate source — a second USB adapter, a bench supply set to 5V, a fresh battery pack. Anything that is not the board you are already using.
  2. Connect that supply's ground to the Arduino's GND. This is not optional, and it is the step people skip.
  3. Leave the two data wires exactly as they are.
  4. Pair and sit there for two minutes.
What happensWhat it means
It holdsThe supply was the problem. Go to cause 1
It still drops after a few secondsThe supply is fine. Go to causes 2, 3 and 4

That is a real fork, and it is worth the two minutes. Everything below is faster once you know which side of it you are on.

Cause 1: the rail is marginal, not missing

If the module holds on its own supply, you are looking for what is loading the shared one.

First, check it is not on the 3.3V pin. The Uno's 3.3V pin is rated for 50 mA in total, for everything — and that is the whole rail, not a per-device budget. Move VCC to the 5V pin. This is not overvolting the module: every one of these modules sits on a breakout board with its own 3.3V regulator, and taking 5V in is precisely what that regulator is for.

If it is already on 5V, look for the other thing drawing current:

  • A motor driver on the same supply. This is the big one, and it is the clearest version of the whole symptom: motors pull amps, and the instant they start the rail dips for everything sharing it. If the link drops exactly when the wheels turn, you have found it.
  • A battery that sags under load. A battery is not a bench supply. Its voltage falls as it delivers current and falls further as it warms, so a pack that measured fine at rest can sit below what the module needs a minute into driving.
  • Long or thin jumper wires. Every centimetre of wire has resistance. It is small, but so is the margin you are working with.

For anything with motors, the supply wiring is not optional detail — it is the design. The battery feeds the motor driver's 12V input and the Arduino's Vin, and the battery, the driver and the Arduino all share a common ground. What the module must never be is downstream of the motor driver's supply, sharing a rail with something that pulls amps.

The genuine limit at the other end is worth stating, because people over-correct: these modules are specified for 3.6–6V, and above 7V destroys them. So 5V is comfortably inside spec, and a 9V battery straight onto VCC is not a fix, it is a replacement part.

Cause 2: the grounds are not common

This is the one that produces the strangest, least repeatable behaviour, and it is invisible because nothing looks wrong.

The test: put a multimeter on continuity and check between the module's GND pin and the Arduino's GND pin. Not between what you think are those two points — between the pins themselves, with the probes on the metal.

If you have added a second power source — the bench supply from the sixty-second test, a battery pack, a powered hub, a second Arduino — and you did not tie its ground to the Arduino's, this is your problem.

Why it matters is worth understanding once. Serial is not a voltage; it is a voltage measured against ground. A logic high is "about five volts more than ground". Two circuits whose grounds are not joined have no shared idea of what zero is, so one side's five volts is the other side's anything-at-all. Sometimes it works. Sometimes it half-works. Often it works until something changes and then it does not, which is exactly what a connection that drops after a few seconds looks like.

Cause 3: the app is quitting, not the module

Before you rewire anything else, find out whether the module dropped or the app did.

The test: connect with a plain serial terminal app instead of whatever you were using. On Android, Serial Bluetooth Terminal is the one to know — free, no account, and it does exactly one thing: pair, send characters, print what comes back. Connect, send a letter, and leave it sitting for two minutes.

If it holds in the terminal app and drops in yours, the module is innocent. Something in your app is closing the socket, backgrounding, or timing out — and no amount of rewiring will change that.

While you are here, take the sketch out of the equation too. Upload this and nothing else:

void setup() {
  Serial.begin(9600);
}
void loop() {
  if (Serial.available()) Serial.write(Serial.read());
}

That is an echo — anything arriving goes straight back out. It has no logic to be wrong, which is the entire point of uploading it. With a terminal app on one end and four lines on the other, a drop can only be the radio, the wiring or the power. If the link holds now and dropped before, the fault was in the sketch you replaced: something in it is resetting the board, blocking for too long, or fighting the module for the serial port.

Classic Bluetooth SPP — which is what an HC-05 and an HC-06 speak — is invisible to iOS at the operating-system level. No app fixes it, no library fixes it, and no wiring change fixes it. You need a BLE module: a genuine HM-10, or an ESP32. And Web Bluetooth is not the escape hatch — it is not in Safari, any version.

So if your module is a Classic one and the phone is an iPhone, there is no terminal app to test with, because there is nothing for it to connect to. Borrow an Android phone for this step.

Cause 4: an MLT-BT05 with a STATE pin that was never connected

This one only bites if your sketch or your app decides "connected" by watching the module's STATE pin, but when it bites it is baffling, because the link is genuinely fine.

The MLT-BT05 — a clone of a clone, sold as an HM-10 — often ships with its STATE pin not connected to anything. Anything reading that pin sees "not connected" permanently. Your code then helpfully tears down a connection that was working, on a schedule, which reads as a module that drops after a few seconds.

The test: ask the module what it is. Open the Serial Monitor at 9600 and send AT+NAME without a question mark, with line ending set to Both NL & CR. A reply of +NAME=MLT-BT05 identifies it. (If that produces nothing at all, the syntax may be inverted for your module — one dropdown decides whether any AT command works.)

The fix: do not build on STATE with this module. Decide "connected" from data actually arriving instead.

The order to work through

#TestIf that is it
1Does it hold on its own supply, grounds tied?Yes → cause 1, the shared rail is marginal
2Continuity between module GND and Arduino GND?No → cause 2, tie the grounds
3Does it hold in a plain terminal app?Yes → cause 3, the app is closing it
4Does AT+NAME answer +NAME=MLT-BT05?Yes → cause 4, stop trusting STATE

Work down it and stop at the first test that changes something. The order runs from the most likely and cheapest to the rarest.

What if none of that was it

If it holds on its own supply, the grounds are common, a terminal app keeps the link for two minutes, and it is not an MLT-BT05, then the connection is not actually the thing that is broken — and it is worth being precise about what you are seeing.

A link that is up but delivers nothing is a different symptom with different causes: crossed or uncrossed data wires, a sketch reading the wrong serial port, or a module whose RXD input was damaged by a full 5V on a line that needs two resistors in one direction and nothing in the other. That last one is worth ruling out if you have ever run the Arduino's TX straight into the module without a divider — the radio survives, so it still pairs and still holds, and only the receiving half is gone.

Every symptom in this subject sorts the same way, by which part of the chain is misbehaving, on the Arduino Bluetooth fixes index.

Common questions

It paired without any trouble, so surely the power is fine?
That is the reasonable assumption and it is wrong. Pairing is the hungriest thing the module ever does — close to 40 mA against the 20 mA it uses while sending and under 8 mA while idle. Surviving that peak once proves the rail can reach it, not that it can hold. A battery that sags as it warms, a motor that starts, or a thin jumper carrying a little more current will all take a marginal rail under afterwards.
How long is a Bluetooth module supposed to stay connected?
Indefinitely. There is no timeout to expire and no session to renew. A paired, idle module draws under 8 mA and will sit there for hours. So a link that drops after a few seconds, and especially one that drops after roughly the same few seconds every time, is not timing out — something is resetting it, and the job is to find out what.
It only drops when the motors start. Is that the same problem?
Yes, and it is the clearest version of it. Motors pull amps, and the moment they start the rail dips for everything sharing it, including the radio. The fix is the wiring from the car build: the battery feeds the motor driver's 12V input and the Arduino's Vin, and the battery, the driver and the Arduino all share a common ground. The module should never be living downstream of a motor driver's supply.
I fitted the divider on both data lines to be safe. Could that cause a drop?
It will break the link, but not in this way. A divider on the module's TX line drags a 3.3V signal down past the Arduino's 3.0V threshold, so the bytes stop arriving — you get silence or garbage while the connection itself stays up. Drops are a power or a ground symptom. Still, take that second divider off: it is doing nothing good.
My app shows disconnected but the module's LED is still blinking slowly. Which is right?
The LED. A slow blink means the module is powered and still holds the connection, so what has failed is the app's idea of the connection rather than the connection itself. On an MLT-BT05 this is routine, because its STATE pin often ships unconnected and anything watching that pin reads disconnected for ever.

Still not connecting?

Arduino Bluetooth — Make It Connect is 62 pages of every way the link fails, why, and the fix — HC-05, HC-06 and HM-10 BLE, including the clone family almost nothing covers. $9.