tl; dr: the LED has a leak path between 3.3V and 5V. Either don't use 5V for the LED, or add a transistor, MOSFET or true open-collector gate to isolate the GPIO and drive the LED.
What’s going on?
If you use a 3.3V GPIO pin to drive a 5V-tied LED, when the GPIO is high it will not be fully 'off': there will still be leakage current between the pin's IO protection and the LED.
Here's what that looks like, and how to fix it:

simulate this circuit – Schematic created using CircuitLab
You’d think that because 5V-3.3V = 1.7V is lower than the LED forward voltage, or Vf, that the LED would not conduct and thus not light up. This is not the case: there will still be some small leakage current that will result in a faint glow. This leakage has a name: subthreshold conduction, and is present in practically all semiconductor devices, including LEDs. Just tens of microamps can make it light.
A note:
- LED forward voltage is usually stated at the LED's rated current (e.g., 20mA). So a '2.0V' red LED like this one will still be conducting at lower voltages, including 1.7V, and even well below that.
- Higher-Vf LEDs (blue, violet, white) will still have some leakage, but less than low-Vf LEDs (red, orange, green)
How do I fix It?
The solution options depend on the LED's forward voltage:
- Low-Vf LED (red, orange, green): use 3.3V supply and drive cathode
- Low-Vf LED (red, orange, green): use GND and drive anode
- High-Vf LED (blue, violet, white) or any other LED: use 5V supply and transistor, MOSFET, or true open-collector gate buffer
All these solutions eliminate the leakage path.
Why use 5V at all?
Using 3.3V for a 3V-ish Vf LED (e.g., white, blue) isn't a good idea as it's very hard to get the current-limiting resistor right: with only 300mV or less IR drop in the resistor, a very small R value must be used, and so the LED current is very sensitive to forward voltage variation.