ESP32 Tutorial: Wi-Fi MAC Address Get and Set
Abstract
Every network-enabled device, including the ESP32, has a unique Media Access Control (MAC) address. The ESP32 actually has two MAC addresses: one for Wi-Fi and one for Bluetooth. This tutorial shows how to programmatically retrieve the default Wi-Fi MAC address and how to permanently set a custom, user-defined MAC address for your ESP32 Wi-Fi interface using the Arduino framework.
1. Introduction to Real-Time Servo Control
In the realm of networked devices, every piece of hardware requires a unique identifier to communicate effectively. For the ESP32—a powerful microcontroller that is the backbone of countless IoT projects—this identifier is the Media Access Control (MAC) address.
A MAC address is a permanent, 48-bit (6-byte) serial number burned into the device’s hardware at the factory, often referred to as the default or base MAC. The ESP32 actually maintains two separate MAC addresses: one for its Wi-Fi interface and one for its Bluetooth interface.
Understanding how to manage these addresses is crucial for various networking tasks, including:
Network Access Control: Implementing MAC address filtering on a router to restrict access to known devices.
Device Tracking: Identifying a specific device consistently within a large network.
Testing and Security: Temporarily changing the device’s identity for testing or privacy reasons (known as MAC spoofing).
This tutorial provides a foundational guide for beginner ESP32 developers, demonstrating the simple Arduino code needed to both programmatically retrieve the default Wi-Fi MAC address and, more importantly, how to use low-level Espressif functions to permanently set a custom, user-defined MAC address for your project.
2. Retrieving the Default MAC Address
The default Wi-Fi MAC address is unique and stored in the ESP32’s internal memory (eFuse). You can retrieve it using the WiFi.macAddress() function after initializing the Wi-Fi module in Station mode (WIFI_STA).
Code to Get MAC Address
#include
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("--- Reading Default Wi-Fi MAC Address ---");
// 1. Initialize Wi-Fi in Station mode (required to read the MAC)
WiFi.mode(WIFI_STA);
// 2. Retrieve the MAC address as a String
String macAddress = WiFi.macAddress();
Serial.print("Default MAC Address: ");
Serial.println(macAddress);
Serial.println("------------------------------------------");
}
void loop() {
// Nothing to do in the loop
}
3. Setting a Custom MAC Address
You might need to set a custom MAC address for specific applications, such as MAC address filtering on a router or for network security reasons. The WiFi.mode() and esp_wifi_set_mac() functions are used together to override the default address.
3.1 Important Notes on Custom MACs
- MAC Format: The MAC address must be exactly 6 bytes (48 bits) in hexadecimal format. It is conventionally written as six pairs of hexadecimal digits separated by colons or hyphens (e.g., AA:BB:CC:11:22:33).
- Multicast/Local Bit: For custom MAC addresses, the second least significant bit of the first byte should typically be set to ‘1’ to indicate a Locally Administered Address. A common convention is to use addresses starting with 02: or 0E: (e.g., 02:FF:AA:BB:CC:DD).
3.2 Code to Set Custom MAC Address
We use the low-level Espressif function esp_wifi_set_mac(), which requires the MAC address to be passed as an array of 6 bytes.
#include
#include // Required for esp_wifi_set_mac()
// --- DEFINE YOUR CUSTOM MAC ADDRESS HERE ---
// Note: This MAC must be provided as an array of 6 bytes (hex).
// The example MAC starts with 0x02 to denote a Locally Administered Address.
uint8_t customMacAddress[] = {0x02, 0xDE, 0xAD, 0xBE, 0xEF, 0x01};
void setup() {
Serial.begin(115200);
delay(1000);
// 1. Initialize Wi-Fi in Station mode
WiFi.mode(WIFI_STA);
// 2. Set the custom MAC address using the low-level function
// The first argument specifies the Wi-Fi interface (WIFI_IF_STA for Station mode)
esp_err_t err = esp_wifi_set_mac(WIFI_IF_STA, customMacAddress);
if (err != ESP_OK) {
Serial.printf("Failed to set MAC address! Error: 0x%x\n", err);
} else {
Serial.println("Custom MAC Address set successfully.");
}
// 3. Verify the new MAC address
String newMacAddress = WiFi.macAddress();
Serial.print("Verified New MAC Address: ");
Serial.println(newMacAddress);
Serial.println("------------------------------------------");
}
void loop() {
// Optional: Add a Wi-Fi connection attempt to confirm functionality
// WiFi.begin("SSID", "PASSWORD");
}
4. Source Code
This project involves two distinct but related code segments: one for reading the MAC and one for writing a custom MAC. Both rely on the standard Wi-Fi library (WiFi.h) and proper initialization of the Wi-Fi mode.
4.1 Retrieving the Default MAC Address
The key to accessing the MAC is initializing the Wi-Fi stack.
| Code Line | Purpose |
#include <WiFi.h> | Includes the standard Arduino library for Wi-Fi functionality. |
WiFi.mode(WIFI_STA); | Critical Step: Initializes the Wi-Fi module in Station mode. The Wi-Fi stack must be started for the MAC address to be accessible by the software functions. |
String macAddress = WiFi.macAddress(); | Retrieval: This high-level Arduino function queries the Wi-Fi stack and returns the currently active MAC address as a String, which is easily printable to the Serial Monitor. |
4.2 Setting a Custom MAC Address
Setting a custom MAC requires using a lower-level function specific to the Espressif SDK (esp_wifi.h), as the basic Arduino Wi-Fi library does not include a direct setter function.
| Code Line | Purpose |
#include <esp_wifi.h> | Includes the required low-level Espressif header for MAC manipulation. |
uint8_t customMacAddress[] = {...}; | Custom MAC Definition: Defines the desired MAC address as an array of 6 bytes (uint8_t), where each pair of hexadecimal digits is an element (e.g., 0xAA, 0xBB, ...). |
WiFi.mode(WIFI_STA); | Initialization: Still required. The Wi-Fi mode must be set before attempting to override the MAC address. |
esp_err_t err = esp_wifi_set_mac(WIFI_IF_STA, customMacAddress); | The Setter Function: This is the core low-level call:<ul><li>WIFI_IF_STA: Specifies that the change applies only to the Station interface.</li><li>customMacAddress: Passes the 6-byte array containing the new MAC.</li><li>esp_err_t: The function returns an error code (ESP_OK if successful) for debugging.</li></ul> |
String newMacAddress = WiFi.macAddress(); | Verification: Calls the standard Arduino getter function (WiFi.macAddress()) again to confirm that the esp_wifi_set_mac command successfully overrode the default address. |
Note on Persistence: The custom MAC address set by esp_wifi_set_mac() is stored in the ESP32’s RAM and is temporary. It will not persist through a power cycle or reset. If a permanent custom MAC is required, the esp_wifi_set_mac() function must be called every time the ESP32 executes the setup() function.
5. Hands-On Lab Recap
You’ve learned how to manage the ESP32’s Wi-Fi MAC address:
- Getting the MAC: Use macAddress() after setting WiFi.mode(WIFI_STA).
- Setting a MAC: Use the low-level function esp_wifi_set_mac(WIFI_IF_STA, mac_array) along with an array of 6 bytes defining your desired MAC address.
- Persistence: The custom MAC address is set in RAM and will persist until the next reset/reboot, at which point it must be set again in the setup()


