Why Does Your Relay Click On When the ESP32 Boots Up? (And How to Fix It)

ESP32 relays glitch on boot because active-low modules trigger when default strapping pins float or pulse high-impedance during resets. Use safe GPIO pins and correct pull resistors to stop accidental switching.
Your relay turns on for a fraction of a second during boot because you are almost certainly using an active-low relay module connected to an ESP32 pin that outputs a high-frequency PWM debug signal, floats high, or acts as a strapping pin while the microcontroller resets. During the 100 to 400 milliseconds before your code executes digitalWrite(pin, HIGH), the relay board's optocoupler sees a path to ground and trips the coil.
In a school greenhouse or an automated desk project, a momentary glitch sounds like an innocent click. In practice, after a routine load-shedding switchover or a brownout reset, that quarter-second glitch can flood an unattended seedling tray, pulse a 12V DC motor, or trigger a high-current mains device.
The Anatomy of an Active-Low Relay Glitch
Most hobbyist relay modules sold across South Africa are "active-low". Their input circuit contains an optocoupler diode with its anode tied permanently to the 5V or 3.3V supply rail via an onboard resistor. To energise the relay, the microcontroller pin must pull low to 0V (ground), allowing current to flow across the diode.
This creates a vulnerable failure mode on power-up:
- High impedance (floating) state: When the ESP32 powers on or recovers from a brownout, its General Purpose Input/Output (GPIO) pins initialise as high-impedance inputs. If internal or external pull-down resistors pull that pin towards ground, the optocoupler conducts immediately.
- ROM bootloader serial logging: By default, the ESP32’s internal bootloader outputs debug messages at 115,200 baud over specific pins immediately upon receiving power. This burst of digital logic looks to an optocoupler like an active signal.
- Delayed setup() execution: Until the FreeRTOS kernel starts and reaches your sketch's
setup()routine—where you explicitly configurepinMode()and hold the pin HIGH—the hardware pin state is dictated entirely by the silicon defaults of the Espressif chip.
The Dangerous Pins: Strapping and Boot-Glitch GPIOs
The standard ESP32 (WROOM-32) has several multi-purpose pins that you should never connect directly to an actuator or relay without external support. Specifically, avoid these pins for switching loads:
| GPIO Pin | Default Power-Up Behaviour | Why It Fails with Relays |
|---|---|---|
| GPIO 0 | Internal weak pull-up; strapping pin for bootloader | Pulls HIGH, but noise or low loads during boot force flash mode. |
| GPIO 2 | Internal weak pull-down; strapping pin; attached to on-board LED | Pulled low at reset; triggers active-low relays instantly on power-up. |
| GPIO 5 | Outputs PWM timing pulse during reset (strapping pin) | Causes an audible, rapid chatter or twitch in relay contacts during boot. |
| GPIO 12 | Internal weak pull-down; strapping pin (voltage selection) | Pulls low at reset; triggers active-low modules. Pulling high externally risks bricking boot. |
| GPIO 15 | Outputs ROM debug log (silent PWM square wave) at boot | Fires active-low relays until firmware fully initialises. |
GPIO pins 34, 35, 36 (VP), and 39 (VN) are input-only pins; they lack internal output drivers entirely and cannot drive a relay module under any circumstances.
The Safe GPIO Pins to Use
If you want quiet, predictable boot behaviour without contact bouncing when power returns, wire your relay signal line to one of the truly neutral general-purpose pins:
- GPIO 18
- GPIO 19
- GPIO 21
- GPIO 22
- GPIO 23
- GPIO 25, 26, 27, 32, 33
None of these pins output ROM serial chatter, and none serve as critical boot mode configuration pins during the first millisecond of silicon startup.
Fixing the Firmware: Order of Operations Matters
Even on a safe pin, standard Arduino-style code often introduces a microscopic glitch due to the order in which commands are written. Many learners write:
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, HIGH); // For active-low: HIGH = OFF
The moment pinMode(..., OUTPUT) executes, the ESP32 defaults the output register to LOW (0V) for several microseconds until the next line executes. On sensitive optocouplers, that microsecond dip is long enough to pull the coil in.
Invert the order in your setup routine so the output buffer is pre-charged before the pin becomes an output:
digitalWrite(RELAY_PIN, HIGH); // Preset state to OFF
pinMode(RELAY_PIN, OUTPUT); // Now engage output driver
The Hardware Fix: External Pull-Up Resistors
Firmware alone cannot protect your load during an unexpected ESP32 crash, a power dip below the 2.7V brownout threshold, or the initial power-rail ramp-up. If your relay controls an inductive water pump or a classroom security latch, rely on hardware.
Place an external 4.7kΩ or 10kΩ pull-up resistor between the ESP32 signal pin and the 3.3V rail. This guarantees the gate or optocoupler stays tied high while the microcontroller starts up, preventing the pin from floating down into the active trigger zone. Alternatively, switch to an active-high relay module, where a floating input remains harmlessly at 0V until your code deliberately asserts 3.3V.
For educators designing automated classroom systems, test benches, or school IoT deployments that must survive uncontrolled power cycles gracefully, Sheen Robotics provides reference schematics and curriculum modules via Sheen IoT to help your learners design resilient systems from the bench up.



