Connecting an ESP32 to WiFi takes four lines of code. Keeping it connected for months, through router reboots, weak signal and power glitches, takes a little more. Most tutorials stop at the four lines, which is why so many projects work perfectly on the desk and then go silent a week after you install them.
This guide covers both halves. You will connect an ESP32 to your network, print its IP address, handle a failed connection properly, make it reconnect on its own, check signal strength, scan for nearby networks, and run the ESP32 as its own access point. Every sketch here works on the standard Arduino-ESP32 core with no extra libraries, and on any ESP32 board, including the DevKit V1, ESP32-S3 and ESP32-C3.
How ESP32 WiFi Works: The Three Modes
The ESP32 has a built-in 2.4 GHz radio (802.11 b/g/n) and can operate in three modes:
| Mode | Constant | What it does | Typical use |
|---|---|---|---|
| Station (STA) | WIFI_STA | Joins your existing router like a phone or laptop | Sensors, web servers, MQTT, cloud APIs |
| Access Point (AP) | WIFI_AP | Creates its own network that others join | Setup pages, no-router projects |
| Station + AP | WIFI_AP_STA | Does both at the same time | Configuration portals, repeaters |
Almost everything you build will use Station mode. One hardware limit is worth knowing up front: the ESP32 only supports 2.4 GHz. It cannot see or join a 5 GHz-only network. Dual-band routers that broadcast one combined name are normally fine, but if your router has separate 2.4 GHz and 5 GHz names, connect the ESP32 to the 2.4 GHz one.
What You Need
- Any ESP32 board (this guide uses a DevKit V1; see the ESP32 pinout guide if you need a pin reference)
- A micro-USB or USB-C data cable
- Arduino IDE with the ESP32 board package installed (Espressif Systems, via Boards Manager)
- The name and password of a 2.4 GHz WiFi network
No extra library is required. The WiFi.h header ships with the ESP32 board package.
Select your board under Tools → Board → ESP32 Arduino → ESP32 Dev Module (or your exact board), pick the correct port, and you are ready.
The Basic Connection Sketch
This is the shortest working version. Replace the two placeholders with your own credentials.
#include <WiFi.h>
const char* ssid = "YOUR_WIFI_NAME";
const char* password = "YOUR_WIFI_PASSWORD";
void setup() {
Serial.begin(115200);
delay(1000);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nConnected!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
}
Upload it, open the Serial Monitor at 115200 baud, and you should see a row of dots followed by an address such as 192.168.1.47. That address is how every other device on your network will reach the ESP32.
Why WiFi.mode(WIFI_STA) first? The ESP32 remembers its previous mode, and an old sketch may have left it in AP mode. Setting the mode explicitly guarantees you start in a known state.
Why this sketch is not good enough for real projects: the while loop waits forever. If the password is wrong, the router is off or the signal is weak, the ESP32 sits there printing dots and never does anything useful.
A Connection Function With a Timeout
A production-ready connect function gives up after a set time and lets the rest of your program decide what to do. This version waits 15 seconds, reports why it failed, and returns true or false.
#include <WiFi.h>
const char* ssid = "YOUR_WIFI_NAME";
const char* password = "YOUR_WIFI_PASSWORD";
bool connectWiFi(uint32_t timeoutMs = 15000) {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
uint32_t start = millis();
while (WiFi.status() != WL_CONNECTED && millis() - start < timeoutMs) {
delay(250);
Serial.print(".");
}
Serial.println();
if (WiFi.status() == WL_CONNECTED) {
Serial.printf("Connected. IP: %s RSSI: %d dBm\n",
WiFi.localIP().toString().c_str(), WiFi.RSSI());
return true;
}
Serial.printf("WiFi failed, status code %d\n", WiFi.status());
return false;
}
void setup() {
Serial.begin(115200);
if (!connectWiFi()) {
Serial.println("Continuing without WiFi...");
}
}
void loop() {
}
The status code tells you what went wrong:
| Status | Value | Meaning |
|---|---|---|
WL_CONNECTED | 3 | Connected and has an IP |
WL_NO_SSID_AVAIL | 1 | The network name was not found (wrong name, out of range, or 5 GHz only) |
WL_CONNECT_FAILED | 4 | Found the network but authentication failed (usually a wrong password) |
WL_CONNECTION_LOST | 5 | Was connected, then lost the link |
WL_DISCONNECTED | 6 | Not connected, often still trying |
For a full diagnosis flow, see our ESP32 WiFi troubleshooting guide.
Automatic Reconnection
Routers reboot, signals dip, and DHCP leases expire. A sketch that connects once in setup() and never checks again will eventually go offline for good. There are two reliable ways to handle it.
Method 1: Check in the loop (simple)
unsigned long lastCheck = 0;
void loop() {
if (millis() - lastCheck > 10000) {
lastCheck = millis();
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi lost, reconnecting...");
WiFi.disconnect();
WiFi.reconnect();
}
}
// your normal code here
}
This uses millis() instead of delay(), so the rest of your program keeps running while WiFi recovers.
Method 2: React to WiFi events (cleaner)
The ESP32 fires events when it connects, gets an IP and disconnects. Registering a handler lets you reconnect the moment the link drops.
void onWiFiEvent(WiFiEvent_t event) {
switch (event) {
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
Serial.print("Got IP: ");
Serial.println(WiFi.localIP());
break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
Serial.println("Disconnected. Reconnecting...");
WiFi.reconnect();
break;
default:
break;
}
}
void setup() {
Serial.begin(115200);
WiFi.onEvent(onWiFiEvent);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
}
Event handlers run in a separate task, so keep them short: print, set a flag, or call reconnect(). Do not put long delays or heavy work inside them.
The ESP32 also has WiFi.setAutoReconnect(true), which is on by default for most cores. It handles simple drops, but it will not rescue you from a changed password or a router that stayed off for hours, so keeping an explicit check in your code is still worth it.
Checking Signal Strength (RSSI)
WiFi.RSSI() returns the received signal strength in dBm. It is a negative number, and closer to zero is better.
| RSSI | Quality | What to expect |
|---|---|---|
| -30 to -50 dBm | Excellent | Fast and stable |
| -50 to -60 dBm | Good | Reliable for most projects |
| -60 to -70 dBm | Fair | Fine for small data, may slow down streaming |
| -70 to -80 dBm | Weak | Frequent drops, slow responses |
| Below -80 dBm | Very poor | Expect disconnects |
Serial.printf("Signal: %d dBm\n", WiFi.RSSI());
If your ESP32 disconnects often and the RSSI is worse than about -75 dBm, no code will fix it. Move the board closer, point the antenna away from metal, or use a board with an external antenna connector.
Scanning for Nearby Networks
Scanning is useful for debugging ("can the ESP32 even see my router?") and for building network pickers.
#include <WiFi.h>
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(100);
Serial.println("Scanning...");
int n = WiFi.scanNetworks();
if (n == 0) {
Serial.println("No networks found");
} else {
for (int i = 0; i < n; i++) {
Serial.printf("%2d: %-32s %4d dBm ch %2d %s\n",
i + 1,
WiFi.SSID(i).c_str(),
WiFi.RSSI(i),
WiFi.channel(i),
WiFi.encryptionType(i) == WIFI_AUTH_OPEN ? "open" : "secured");
}
}
}
void loop() {
}
If your network does not appear in this list, the ESP32 cannot connect to it. The usual reasons are that your router is broadcasting only on 5 GHz, the network name is hidden, or the board is simply too far away.
Running the ESP32 as an Access Point
In AP mode the ESP32 creates its own WiFi network. Phones and laptops join it directly, with no router needed. This is how you build setup pages, local control panels and projects for places without internet.
#include <WiFi.h>
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_AP);
bool ok = WiFi.softAP("ESP32-Setup", "12345678"); // password: 8+ characters
Serial.println(ok ? "Access point started" : "AP failed");
Serial.print("AP IP address: ");
Serial.println(WiFi.softAPIP()); // default: 192.168.4.1
}
void loop() {
}
Join ESP32-Setup from your phone and the ESP32 is reachable at 192.168.4.1. The password must be at least 8 characters. Pass NULL as the password to create an open network. A single ESP32 accepts only a handful of simultaneous clients (the default limit is 4, and the maximum is 10), so AP mode suits control panels rather than shared hotspots.
If you want users to type their home WiFi details into a web page instead of editing code, read the WiFiManager captive portal guide.
Good Habits for Real Projects
Keep credentials out of your main sketch. Put them in a separate secrets.h file and add that file to .gitignore so you never publish your WiFi password by accident.
// secrets.h
#define WIFI_SSID "YOUR_WIFI_NAME"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWORD"
#include "secrets.h"
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Set a hostname. A name like esp32-garage is much easier to spot in your router's device list than espressif. Call WiFi.setHostname("esp32-garage"); after WiFi.mode(WIFI_STA) and before WiFi.begin().
Give it a fixed address when other things depend on it. Home Assistant, dashboards and port forwarding all work better if the ESP32 always has the same IP. See the static IP guide.
Do not use delay() for long waits. Use millis() timing so WiFi tasks and your own code keep running.
Mind the power supply. The WiFi radio draws current spikes of roughly 300 to 400 mA while transmitting. A weak USB port or long thin cable causes brownouts that look exactly like WiFi bugs.
Frequently Asked Questions
Can the ESP32 connect to 5 GHz WiFi? No. The original ESP32, ESP32-S3 and ESP32-C3 are 2.4 GHz only. Newer parts such as the ESP32-C5 add 5 GHz, but the common boards do not.
Why does my ESP32 connect but show "IP: 0.0.0.0"? It joined the network but did not receive an address from DHCP yet. Wait a second and read the IP again, or check your router's DHCP settings.
Can I use WiFi and Bluetooth together? Yes, but they share one radio and memory, so both slow down and RAM gets tight. The BLE-only or WiFi-only designs are far more stable.
Does WiFi block my analog readings? On ADC2 pins, yes. Use ADC1 pins (GPIO 32 to 39) whenever WiFi is active. Details in the ESP32 ADC guide.
What is the next step after connecting? Serve a web page, talk to an API, or publish data. Good follow-ups are HTTP GET and POST requests, MQTT, and WebSockets for real-time data.