
Joining has stages
Joining a Wi-Fi network is a ladder of stages, from the scan through association and the four-way handshake to an address from DHCP. Connected and got IP are two events, and each failure has its own reason.
A ladder, not a switch
Joining a WPA2-Personal network takes five steps, and four of them are Wi-Fi. The board scans for the network's name. It sends an 802.11 authentication frame, which on WPA2-Personal is Open System: a formality kept from 1997 that checks no password. It associates, and the access point gives it an association ID, a number from 1 to 2007 on its list. That number is not an IP address.
Then the four-way handshake. The access point sends a random number, the ANonce, and the board sends its own, the SNonce. Each side mixes the two with a key made from the passphrase and with both MAC addresses, and each proves with a check value that it reached the same result. The passphrase never crosses the air, and it is not itself the key.
The fifth step is DHCP, which is not part of Wi-Fi at all. It is an IP protocol that rides on the link once the link exists; a static address skips it.
Two events, two moments
ESP-IDF reports the end of the Wi-Fi part as WIFI_EVENT_STA_CONNECTED. Only then does it start the DHCP client, and IP_EVENT_STA_GOT_IP arrives when an address does. Socket code has to wait for the second. In between, DHCP can be slow or fail, and the board sits on the network with no address to talk with.
Arduino-ESP32 hides the gap. In the 3.x core, WL_CONNECTED is set only when the board gets an address. And WiFi.begin() starts the join and returns at once, without waiting: check WiFi.status() or wait for the event.
Each failure has a reason
A failed join raises WIFI_EVENT_STA_DISCONNECTED with a reason code. A wrong password gets as far as association and fails at the handshake, because the two sides worked out different keys; it usually shows as a handshake timeout, reason 15 or 204. A name the scan never found is 201, NO_AP_FOUND, which also appears when a password is set for an open network or none for a secured one. A network that was found but whose security does not match is 210, in ESP-IDF 5.2 and later.
Print the reason before you change the code. Station mode in the ESP32 book has the code that does.
The handshake arrived with 802.11i, approved on 24 June 2004 and certified by the Wi-Fi Alliance as WPA2.
Common mistakes
- Opening a socket on
WIFI_EVENT_STA_CONNECTED. The board has no address until got IP. Wait for the second event. - Using the network on the line after
WiFi.begin(). It returns before the join is done. Wait forWL_CONNECTED. - Changing the password when the reason is 201. The scan never found the name, so the password was never tested. Check the name, the band and the distance first.
Edit this page — content/fundamentals/wifi/joining-has-stages.mdx
Discuss this article
Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.