The Direct Answer: Which Arduino Solenoid Driver to Pick

An Arduino GPIO pin outputs 5V at a maximum safe continuous current of 20mA. A standard 12V water or air solenoid valve draws between 1A and 2A. You cannot wire a solenoid directly to an Arduino pin; doing so will instantly destroy the ATmega328P microcontroller. You need a driver circuit.

Use this decision tree to select the correct driver for your specific hardware.

Solenoid Spec Driver Type Concrete Pick (Part Number)
5V DC, < 200mA (Micro valves) Direct GPIO Drive None (Wire directly to D9 via 220Ω resistor)
5V-24V DC, < 5A (Standard irrigation/pneumatic) Logic-Level N-Channel MOSFET IRLZ44N (Default Pick)
12V-24V DC, > 5A (High-flow industrial) High-Current Relay or MOSFET Module Songle SRD-12VDC-SL-C (30A Relay)
24V-120V AC (HVAC/Industrial valves) Solid State Relay (SSR) Omron G3NA-210B-DC5-24
The Default Pick: For 90% of DIY irrigation, pneumatic, and fluid control projects using a 12V DC solenoid drawing under 3A, use the IRLZ44N logic-level MOSFET. It fully turns on (low Rds(on)) at the 5V output of an Arduino GPIO, unlike standard MOSFETs like the IRF520 which require 10V+ to fully saturate and will overheat when driven by 5V logic.

Parts List & Spec Sheet

This build assumes a standard 12V DC brass water valve. Prices are approximate based on 2026 component market rates.

Component Exact Variant / Model Critical Spec Est. Price
Microcontroller Arduino Uno R3 (DIP-28 ATmega328P) 5V logic, 20mA max GPIO $24.00
Driver IRLZ44N N-Channel MOSFET (TO-220) Vgs(th) max 2.0V, Id 47A $1.50
Flyback Diode 1N4007 Rectifier Diode 1000V PIV, 1A forward current $0.10
Resistors 220Ω and 10kΩ (1/4W Carbon Film) Gate protection and pull-down $0.05
Power Supply 12V 2A Switching PSU (Barrel Jack) 24W max output, 5.5mm x 2.1mm plug $8.00
Solenoid Valve US Solid 1/2' NPT 12V DC (Normally Closed) 12V DC, ~1.2A draw, 11.5W $14.00

Wiring the Arduino Solenoid Circuit

Safety Note: While 12V DC is safe from an electrocution standpoint, a 1.2A continuous current will melt standard 24 AWG breadboard jumper wires over time. Use at least 18 AWG stranded wire for the 12V power loop (PSU to Solenoid to MOSFET Drain), and solder the connections if this is a permanent installation.

Pin Mapping Table

Arduino Uno R3 Pin Connects To Purpose
D9 (PWM capable) 220Ω Resistor -> MOSFET Gate Logic signal to switch the valve
GND 10kΩ Resistor -> MOSFET Gate & PSU GND Shared reference ground & gate pull-down
5V (Not used for solenoid power) Do NOT power the solenoid from the Arduino 5V rail

Step-by-Step Wiring Procedure

  1. Establish Common Ground: Connect the GND terminal of your 12V external power supply directly to one of the Arduino Uno's GND pins. If you skip this, the MOSFET gate will not have a reference voltage and the valve will not switch.
  2. Wire the Gate Pull-Down: Connect a 10kΩ resistor between the MOSFET Gate (middle pin) and GND. This ensures the valve stays closed if the Arduino reboots or the pin floats during startup.
  3. Wire the Gate Signal: Connect a 220Ω resistor between Arduino D9 and the MOSFET Gate. This limits inrush current into the gate's internal capacitance, protecting the ATmega328P GPIO.
  4. Wire the Solenoid Power Loop: Connect the 12V PSU positive terminal to one terminal of the solenoid valve.
  5. Wire the MOSFET Drain: Connect the other terminal of the solenoid valve to the MOSFET Drain (left pin, tab facing you).
  6. Wire the MOSFET Source: Connect the MOSFET Source (right pin) to the shared GND rail.
  7. Install the Flyback Diode: Place the 1N4007 diode in parallel with the solenoid coil. The cathode (silver stripe) must point toward the 12V positive side, and the anode must point toward the MOSFET Drain. Reversing this will cause a dead short and blow your power supply fuse.
Pro-Tip: For a deeper understanding of why the flyback diode is non-negotiable, review the physics of inductive kickback in the All About Circuits flyback diode guide. A collapsing magnetic field generates a voltage spike that can exceed 100V, instantly piercing the MOSFET's drain-source junction.

Complete Arduino Solenoid Code

This code targets the Arduino Uno R3 (ATmega328P). It uses a non-blocking millis() timer to pulse the solenoid and includes a critical safety feature: a maximum runtime limit. If your code logic hangs or a sensor fails, the solenoid will automatically shut off to prevent flooding or coil burnout.

// Target Board: Arduino Uno R3 (ATmega328P)
// Project: 12V Solenoid Valve Non-Blocking Control

const int SOLENOID_PIN = 9;
const int BUTTON_PIN = 2; // Optional manual override button

// Timing variables (milliseconds)
unsigned long previousMillis = 0;
unsigned long solenoidStartTime = 0;
const unsigned long PULSE_DURATION = 5000; // Open for 5 seconds
const unsigned long MAX_RUNTIME = 60000;   // Safety cutoff: 60 seconds max

bool solenoidState = false;
bool pulseActive = false;

void setup() {
  Serial.begin(9600);
  
  // Pin configuration
  pinMode(SOLENOID_PIN, OUTPUT);
  pinMode(BUTTON_PIN, INPUT_PULLUP); // Active LOW button
  
  // Ensure valve is closed on boot
  digitalWrite(SOLENOID_PIN, LOW);
  
  Serial.println("System Initialized. Solenoid closed.");
}

void loop() {
  unsigned long currentMillis = millis();
  
  // Read manual override button (debounced implicitly by state change check)
  bool buttonPressed = (digitalRead(BUTTON_PIN) == LOW);
  
  // Trigger a new pulse if button is pressed and no pulse is currently active
  if (buttonPressed && !pulseActive) {
    openSolenoid(currentMillis);
  }
  
  // Handle active pulse timing
  if (pulseActive) {
    unsigned long timeElapsed = currentMillis - solenoidStartTime;
    
    // Normal completion
    if (timeElapsed >= PULSE_DURATION) {
      closeSolenoid("Pulse duration complete.");
    }
    
    // Safety Error Handling: Hard cutoff to prevent flooding
    if (timeElapsed >= MAX_RUNTIME) {
      closeSolenoid("ERROR: Max runtime exceeded. Forcing close.");
      // Add a delay to prevent immediate re-triggering if button is stuck
      delay(2000); 
    }
  }
}

void openSolenoid(unsigned long currentTime) {
  digitalWrite(SOLENOID_PIN, HIGH);
  solenoidState = true;
  pulseActive = true;
  solenoidStartTime = currentTime;
  Serial.println("Solenoid OPENED.");
}

void closeSolenoid(String reason) {
  digitalWrite(SOLENOID_PIN, LOW);
  solenoidState = false;
  pulseActive = false;
  Serial.print("Solenoid CLOSED. Reason: ");
  Serial.println(reason);
}

Debugging: First 3 Things to Check When It Fails

The most common failure mode in solenoid circuits is the Arduino resetting when the solenoid fires. On the Arduino Uno R3, this manifests as the Serial monitor clearing and re-printing the setup() initialization text. If you swap to an ESP32, the serial monitor will output the exact error string: Brownout detector was triggered followed by rst cause:4.

This happens because inductive kickback or voltage sag on the 12V rail is coupling back into the Arduino's 5V logic rail, triggering the microcontroller's internal Brownout Detector (BOD). Check these three things in order:

1. The Flyback Diode is Missing or Reversed

The Fix: Verify the 1N4007 diode is physically across the solenoid coil (not across the MOSFET). Ensure the silver stripe (cathode) faces the 12V positive wire. If the diode is backwards, it acts as a dead short when the MOSFET turns on, causing the PSU to fold back its voltage, which starves the Arduino of power and causes a brownout reset.

2. You Used a Standard MOSFET Instead of Logic-Level

The Fix: Check the part number printed on your transistor. If it says IRF520 or IRFZ44N, throw it in the bin and buy an IRLZ44N (the 'L' stands for Logic-level). Standard MOSFETs require 10V on the gate to fully open. Driven by a 5V Arduino, they operate in their linear (high-resistance) region. They will get blisteringly hot, fail to pass enough current to pull in the solenoid, and can cause ground-bounce that resets the Arduino. (Reference the Arduino transistor guide for more on Vgs thresholds).

3. Missing Common Ground or Undersized Power Supply

The Fix: Measure the voltage between the Arduino GND pin and the 12V PSU GND terminal with a multimeter while the solenoid is firing. It should read < 0.1V. If it reads higher, your ground wire is too thin. Furthermore, ensure your 12V PSU is rated for at least 2A. A 500mA PSU will experience severe voltage droop when the solenoid's inrush current hits, collapsing the 5V regulator on the Arduino board.

Extending and Simplifying the Build

How to Simplify (The Relay Alternative)

If you don't want to deal with raw MOSFETs, gate resistors, and loose diodes, simplify the build by using a pre-assembled 5V Optocoupler Relay Module (featuring the Songle SRD-05VDC-SL-C relay).

  • Wiring: Connect VCC to Arduino 5V, GND to Arduino GND, and IN to D9.
  • Solenoid Loop: Wire the 12V PSU and solenoid through the relay's COM (Common) and NO (Normally Open) screw terminals.
  • Trade-off: The relay module includes its own built-in flyback diode and optocoupler isolation, making it virtually bulletproof against brownouts. However, mechanical relays are rated for roughly 100,000 click cycles and are louder than a solid-state MOSFET.

How to Extend (Automated Scheduling)

To turn this manual push-button circuit into an automated irrigation system, add a DS3231 I2C Real Time Clock (RTC) module.

  • Wire the DS3231 SDA to A4 and SCL to A5 on the Uno R3.
  • Use the RTClib library to read the current time.
  • Add logic to the loop() to trigger the openSolenoid() function at specific hours (e.g., 06:00 AM and 06:00 PM).
  • Pro-Tip: Add a soil moisture sensor (analog output to A0) and implement hysteresis. Only allow the RTC to open the solenoid if the soil moisture reading is below 30%, preventing overwatering during rain events.