If you just yank the USB-C cable to turn off your Raspberry Pi, you are begging for SD card corruption and file system errors. Adding a physical power on switch raspberry pi setup is one of the first upgrades you should make to any headless build, kiosk, or portable project. But the Pi doesn't have a native power switch on the board—at least, the older models don't.
The direct answer: For the Raspberry Pi 4 Model B, wire a momentary pushbutton between Pin 5 (GPIO 3)Pin 6 (GND), then use a Python gpiozero script to trigger a safe OS shutdown. Pin 5 is hardware-wired to the Power Management IC (PMIC) to wake the Pi from a halted state. For the Raspberry Pi 5, you bypass the GPIO entirely and wire your switch directly to the dedicated PWR header pins near the USB-C port.
This guide walks through the exact bench procedure, the systemd service configuration, and the edge cases that usually trip up first-time builders.
Parts List & Hardware Requirements
Time to Complete: 45 minutes.
Before you start stripping wires, gather these exact components. Prices reflect typical 2026 hobbyist market rates.
| Component | Specification / Variant | Est. Price |
|---|---|---|
| Microcontroller | Raspberry Pi 4 Model B (4GB or 8GB) or Pi 5 | $55 - $80 |
| Switch | 12mm SPST Momentary Pushbutton (Normally Open) | $1.50 |
| Wiring | 22 AWG stranded hook-up wire or female-to-female Dupont | $3.00 |
| Resistor (Optional) | 10kΩ through-hole (Only if using a custom GPIO pin, not Pin 5) | $0.10 |
| Power Supply | Official 5.1V 3A USB-C PSU (Crucial for stable PMIC wake) | $12.00 |
Pin Mapping & Wiring the Switch
The secret to a true 'power on' capability on the Pi 4 lies in the I2C1 SCL line. Pin 5 (BCM GPIO 3) has a physical 2.2kΩ pull-up resistor to 3.3V on the Pi PCB. More importantly, it is hardwired to the PMIC. When the Pi is fully halted, pulling this pin LOW (connecting it to ground) signals the PMIC to boot the board. No other GPIO pin can wake a fully halted Pi 4 without keeping the SoC in a low-power sleep state.
| Pi 4 Physical Pin | BCM GPIO | Function | Switch Connection |
|---|---|---|---|
| Pin 5 | GPIO 3 (SCL1) | I2C Clock / PMIC Wake | Switch Leg 1 |
| Pin 6 | GND | Ground Reference | Switch Leg 2 |
Wiring Steps
- De-energize the board: Unplug the USB-C power supply. Never hot-swap GPIO connections while the Pi is running.
- Prepare the switch: Solder your 22 AWG wires to the two normally-open (NO) legs of your momentary pushbutton. Use heat shrink tubing to prevent stray strands from shorting against the Pi's metal USB ports.
- Connect to GPIO: Plug the first wire into Pin 5 and the second into Pin 6. Polarity does not matter for a mechanical switch.
- Verify continuity: Set your multimeter to continuity mode. Place probes on the wire ends. It should read open (OL). Press the button; it should beep (< 1 ohm).
The Python Safe Shutdown Script
We use the gpiozero library because it handles debouncing and pin cleanup natively. Because Pin 5 has a hardware pull-up, we must explicitly tell gpiozero not to fight it by setting pull_up=False and active_state=False.
Target Board: Raspberry Pi 4 Model B running Raspberry Pi OS (Bookworm or newer, 64-bit).
#!/usr/bin/env python3
import os
import sys
import signal
import logging
from gpiozero import Button
from time import sleep
# BCM GPIO 3 (Physical Pin 5) is hardware-wired to wake the Pi 4 from halt
POWER_BUTTON_PIN = 3
HOLD_TIME = 2.0 # Seconds to hold before triggering shutdown
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[logging.FileHandler('/var/log/pipwr.log'), logging.StreamHandler()]
)
def shutdown_pi():
logging.info('Shutdown sequence initiated by power button.')
try:
# Sync filesystems before halting to prevent SD card corruption
os.system('/bin/sync')
os.system('/sbin/shutdown -h now')
except Exception as e:
logging.error(f'Failed to execute shutdown: {e}')
sys.exit(1)
def signal_handler(sig, frame):
logging.info('Service stopping, cleaning up GPIO listeners.')
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
try:
# pull_up=False disables internal pull-up (Pin 5 has a 2.2k hardware pull-up)
# active_state=False means the button is 'pressed' when pulled LOW to GND
btn = Button(
POWER_BUTTON_PIN,
hold_time=HOLD_TIME,
pull_up=False,
active_state=False
)
btn.when_held = shutdown_pi
logging.info(f'Power switch listener active on BCM GPIO {POWER_BUTTON_PIN}.')
# Keep the script running to listen for interrupts
signal.pause()
except RuntimeError as e:
if 'No access to /dev/mem' in str(e):
logging.error('RuntimeError: No access to /dev/mem. Try running as root!')
else:
logging.error(f'GPIO Initialization Error: {e}')
sys.exit(1)
except Exception as e:
logging.error(f'Unexpected fatal error: {e}')
sys.exit(1)
Deploying as a Systemd Service
To ensure the switch works on every boot, wrap the script in a systemd service.
- Save the code above to
/usr/local/bin/pipwr.pyand make it executable:sudo chmod +x /usr/local/bin/pipwr.py. - Create the service file:
sudo nano /etc/systemd/system/pipwr.service. - Paste the following configuration:
[Unit] Description=Raspberry Pi Power Button Safe Shutdown After=multi-user.target [Service] ExecStart=/usr/bin/python3 /usr/local/bin/pipwr.py Restart=on-failure User=root [Install] WantedBy=multi-user.target - Enable and start:
sudo systemctl enable pipwr.servicethensudo systemctl start pipwr.service.
Troubleshooting: When the Switch Fails
If you press the button and nothing happens, or the Pi shuts down but refuses to wake up, work through these ranked causes.
The First Three Things to Check
- Systemd Service Status: Run
sudo systemctl status pipwr. If it's dead, check the logs withjournalctl -u pipwr -e. - I2C Interface Conflict: Pin 5 is the I2C1 SCL line. If you enabled the I2C interface in
raspi-configand have another device on the bus, it can interfere with the voltage drop. Disable I2C if you aren't using it. - Power Supply Voltage Sag: The PMIC requires stable 5V to register the wake signal. If you are using a cheap phone charger that drops to 4.6V under load, the Pi will halt but the PMIC brownout protection will prevent the wake trigger. Use the official 5.1V PSU.
Exact Error Strings & Fixes
| Exact Error String | Root Cause | Fix |
|---|---|---|
RuntimeError: No access to /dev/mem. Try running as root! | The Python script is running as the standard 'pi' user, but GPIO memory mapping requires root privileges on newer Pi OS kernels. | Ensure your systemd service specifies User=root, or run the script manually with sudo. |
gpiozero.exc.PinFactoryFallback: Falling back from rpigpio | The underlying RPi.GPIO library is missing or incompatible with the 64-bit Bookworm kernel. | Install the fallback dependencies: sudo apt install python3-rpi.gpio or switch to the lgpio backend which is native to Bookworm. |
Extending and Simplifying the Build
Simplifying: The Raspberry Pi 5 Native PWR Header
If you are building this on a Raspberry Pi 5, you can delete the Python script entirely. The Pi 5 features a dedicated power management IC (DA9091) and a physical PWR header located just behind the USB-C port. Simply wire your momentary switch directly to the two pins on the PWR header. The firmware handles the 2-second hold for safe shutdown, the double-tap for hard reset, and the wake-from-halt logic natively. No code required.
Extending: Adding an LED Status Indicator
Want to know if the Pi is running or halted? Wire a 3mm LED with a 220Ω current-limiting resistor between Pin 1 (3.3V) and GPIO 24 (Pin 18). Add led = LED(24) to your Python script, and use led.blink() during the shutdown sequence to provide visual feedback that the OS is safely writing to the SD card before cutting power.
Frequently Asked Questions
Can I use a standard latching toggle switch for Raspberry Pi power?
No, not directly on the GPIO pins. A latching (maintained) toggle switch will hold Pin 5 LOW continuously. The Pi will boot, the script will immediately read the LOW state, and trigger a shutdown loop. You must use a momentary (normally open) pushbutton. If you absolutely want a toggle switch experience, you need a hardware latching relay circuit or a dedicated HAT like the Pi Supply Switch that manages the power rail independently of the GPIO logic.
Why does my Raspberry Pi reboot immediately after I press the shutdown switch?
This is almost always caused by a noisy switch or a missing pull-up resistor. When the mechanical contacts bounce during release, they can create a secondary LOW pulse that the PMIC interprets as a 'wake' command immediately after the halt sequence finishes. The Pi 4's hardware 2.2kΩ pull-up on Pin 5 usually prevents this, but if your wires are long (over 6 inches), they act as antennas. Solder a 100nF ceramic capacitor across the switch legs to debounce the hardware signal, or increase the HOLD_TIME in the Python script to 3.0 seconds.
How do I wire a power switch for a Pi in a metal enclosure?
Do not mount a metal pushbutton directly to a metal chassis without isolation. If the switch casing touches the chassis, and the chassis grounds to the Pi's GND via the mounting standoffs, you will short Pin 5 to GND permanently, causing a boot-loop or preventing the Pi from starting. Use a plastic isolation washer, or buy a panel-mount switch with a plastic threaded bushing. Always verify chassis isolation with a multimeter before applying power.






