By default your ESP32 asks the router for an address every time it connects, and the router hands out whatever is free. Most of the time you get the same one back. Then one day the router restarts, or a new phone joins the network first, and your ESP32 turns up at a different address. The bookmark to its web page stops working, Home Assistant loses the device, a port forward points at nothing and your MQTT client config is suddenly wrong.
A static IP address solves that. There are two ways to do it, and they are not equal. One lives on your router and is almost always the better choice. The other lives in your sketch and is the better choice in a few specific cases. This guide shows both, explains the gateway, subnet and DNS values that trip people up, and covers what to do when the ESP32 will not connect after you set a static address.
Two Ways to Get a Fixed IP
| Method | Where it is set | Best for | Weakness |
|---|---|---|---|
| DHCP reservation | Router admin page | Almost everyone | Needs router access |
| Static IP in code | WiFi.config() in the sketch | No router access, hotspots, devices moving between known networks | Wrong values break the connection, and the address is baked into the firmware |
The recommendation: use a DHCP reservation. The ESP32 stays a normal DHCP client, the router always gives it the same address, and nothing in your code can go wrong. If you ever move the device to another network, the sketch works unchanged.
Use the in-code method when you cannot touch the router (a shared or rented network, a phone hotspot with predictable subnets) or when you want the ESP32 to connect a little faster by skipping the DHCP exchange.
Method 1: DHCP Reservation on Your Router (Recommended)
The steps differ slightly per router brand, but the idea is always the same:
- Connect the ESP32 to your network normally and print its MAC address:
#include <WiFi.h>
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
Serial.print("MAC address: ");
Serial.println(WiFi.macAddress());
}
void loop() {
}
- Open your router's admin page, usually
192.168.1.1,192.168.0.1or192.168.1.254. The address is printed on a sticker on the router. - Find a section called DHCP, LAN, Address Reservation, Static Leases or Device List.
- Select the ESP32 from the list of connected clients (or enter its MAC address) and assign the address you want, for example
192.168.1.184. - Save, then reboot the ESP32. It will come back at the reserved address.
Pick an address inside your subnet (the same first three numbers as your router) and preferably outside the router's automatic DHCP range, so it is never given to another device first. If your router hands out addresses from 192.168.1.100 to 192.168.1.200, then 192.168.1.50 or 192.168.1.250 are safe choices.
Because the setting lives in the router, this method keeps your sketch completely standard. It is also the approach recommended in our ESP32-CAM web server guide.
Method 2: Static IP in Code With WiFi.config()
You need four values from your network:
| Value | What it is | Typical example |
|---|---|---|
| Local IP | The address you want the ESP32 to have | 192.168.1.184 |
| Gateway | Your router's address | 192.168.1.1 |
| Subnet mask | Defines the local network size | 255.255.255.0 |
| DNS | Server that resolves names to addresses | 192.168.1.1 (the router) or 8.8.8.8 |
Find your gateway and subnet
On the same network, from a computer:
- Windows: open Command Prompt and run
ipconfig. Read "Default Gateway" and "Subnet Mask". - Mac or Linux: run
ip routeorifconfig. On macOS,netstat -nr | grep defaultshows the gateway. - Phone: WiFi settings, tap the connected network, and look for Router or Gateway.
Or let the ESP32 tell you: connect it once with DHCP and print WiFi.gatewayIP(), WiFi.subnetMask() and WiFi.dnsIP().
The code
#include <WiFi.h>
const char* ssid = "YOUR_WIFI_NAME";
const char* password = "YOUR_WIFI_PASSWORD";
IPAddress local_IP(192, 168, 1, 184);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress primaryDNS(8, 8, 8, 8); // optional but recommended
IPAddress secondaryDNS(8, 8, 4, 4); // optional
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
Serial.println("Static IP configuration failed");
}
WiFi.begin(ssid, password);
Serial.print("Connecting");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nConnected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
}
Order matters. WiFi.config() must be called before WiFi.begin(). If you call it afterward it has no effect.
Do not forget DNS. If you skip the DNS arguments, the ESP32 can reach devices by IP address but fails to resolve names such as api.openweathermap.org or broker.hivemq.com. This is the classic "static IP breaks my internet requests" bug. Passing a DNS server fixes it.
Test It: A Web Page at Your Fixed Address
This sketch serves a page at the static IP, proving the address works from any device on the network.
#include <WiFi.h>
#include <WebServer.h>
const char* ssid = "YOUR_WIFI_NAME";
const char* password = "YOUR_WIFI_PASSWORD";
IPAddress local_IP(192, 168, 1, 184);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress dns(8, 8, 8, 8);
WebServer server(80);
void handleRoot() {
String html = "<h1>ESP32 is alive</h1><p>IP: " + WiFi.localIP().toString() + "</p>";
server.send(200, "text/html", html);
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.config(local_IP, gateway, subnet, dns);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) delay(500);
Serial.print("Open http://");
Serial.println(WiFi.localIP());
server.on("/", handleRoot);
server.begin();
}
void loop() {
server.handleClient();
}
Open the printed address in a browser on a phone or computer on the same WiFi. You can also test from a computer with ping 192.168.1.184. A reply means the address is reachable.
Use a Name Instead: mDNS
Remembering numbers is awkward. The ESP32 can announce a friendly name through mDNS, so you open http://esp32.local instead of an IP.
#include <ESPmDNS.h>
void setup() {
// ...after WiFi is connected
if (MDNS.begin("esp32")) {
Serial.println("Open http://esp32.local");
}
}
mDNS works on macOS, iOS, Linux (with Avahi) and modern Windows. Android support is inconsistent, so keep the IP as a backup. Note that mDNS is a convenience, not a replacement for a stable address. Tools such as Home Assistant and MQTT clients behave better with a fixed IP.
Choosing Good Addresses
- Keep a short written list:
.50garage camera,.51greenhouse sensor,.52hallway switch. Future you will be grateful. - Stay out of the router's automatic range to avoid conflicts.
- Never use
.0(the network),.255(broadcast) or the router's own address. - Do not give two devices the same address. Duplicate addresses make both devices flap on and off.
Troubleshooting Static IP Problems
"STA Failed to configure" or WiFi.config() returns false. Check that all four IPAddress values are valid and that WiFi.mode(WIFI_STA) is called first.
It never connects after adding WiFi.config(). The address is outside your real subnet. If your router is 192.168.0.1, an address like 192.168.1.184 will never work. Match the first three numbers.
It connects but the internet or MQTT broker is unreachable. Missing DNS, or the wrong gateway. Add the DNS arguments and double-check the gateway.
It connects, then drops, then reconnects constantly. Another device already has the same address. Choose a different one and check your router's client list.
Works at home, fails at another location. Static addresses belong to one subnet. Move to a DHCP reservation, or write the sketch to fall back to DHCP if the static connection fails.
Router shows a different IP than the sketch. The router reservation is overriding your code, or the sketch is not reaching WiFi.config() first. Choose one method and remove the other.
Cannot reach the ESP32 from the internet. A local IP is private. For remote access, use a VPN back into your network or a cloud service. Forwarding ports straight to a device without authentication is risky.
If connection issues persist, work through the ESP32 WiFi troubleshooting guide.
A Safe Pattern: Try Static, Fall Back to DHCP
For portable projects, attempt the static address first and fall back automatically:
bool connectWithFallback(uint32_t timeoutMs = 10000) {
WiFi.mode(WIFI_STA);
WiFi.config(local_IP, gateway, subnet, dns);
WiFi.begin(ssid, password);
uint32_t start = millis();
while (WiFi.status() != WL_CONNECTED && millis() - start < timeoutMs) delay(250);
if (WiFi.status() == WL_CONNECTED) return true;
// fall back to DHCP
WiFi.disconnect(true);
WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); // clear static settings
WiFi.begin(ssid, password);
start = millis();
while (WiFi.status() != WL_CONNECTED && millis() - start < timeoutMs) delay(250);
return WiFi.status() == WL_CONNECTED;
}
The INADDR_NONE call resets the interface to DHCP, so the same firmware works on networks where your chosen address is not valid.
Frequently Asked Questions
Is a static IP faster? Slightly. The ESP32 skips the DHCP exchange, saving a fraction of a second on connection.
Do I need a static IP for Home Assistant? It is strongly recommended. Home Assistant and MQTT setups are far more reliable when the device address never changes. See the MQTT and Home Assistant guide.
Does the static IP survive a reboot or a power cut? Yes. It is part of your firmware (or stored in your router), not in volatile memory.
Can I set a static IP in access point mode? Yes, with WiFi.softAPConfig(local_ip, gateway, subnet). The default AP address is already a fixed 192.168.4.1.
What if I want users to enter their own address? Combine this guide with a configuration portal. See the WiFiManager guide.
Continue with the ESP32 WiFi tutorial for reconnection logic and signal strength.