ESPHome 2026.9 Finally Encrypts OTA Updates. Here Is the Two-Step Migration That Can Strand a Device

Close-up of microchips and components on a dark circuit board

Most of my ESPHome devices have an api: block with an encryption key, and I have long felt good about that. Then I looked at the ota: block underneath it and saw a plain password, the same one copy-pasted into a dozen YAML files. ESPHome 2026.9, released on 16 September, finally closes that gap, and it comes with a migration trap that is worth understanding before you click “Update all”.

What actually changed

Until now, the OTA platform authenticated with a password, but the firmware transfer itself was not encrypted. As of 2026.9 the esphome OTA platform uses Noise (ChaCha20-Poly1305), the same scheme the native API already uses. According to the release notes, any device that has an api: encryption key now offers encrypted OTA automatically, and the ESPHome CLI uses it when it is offered. You do not have to touch your YAML for that part.

If you want to make it mandatory, you add a bare encryption: under ota:. It reuses your API key, and it cannot be combined with password:.

api:
  encryption:
    key: !secret api_key

ota:
  - platform: esphome
    encryption:

That is the whole end state: one key, no separate OTA password to rotate, leak or forget.

The two-step migration (this is the part that bites)

You cannot jump straight from a password to encryption: on a device that is still running older firmware, because that firmware does not know how to speak the encrypted protocol. The release notes spell out the order:

  • Update the device to 2026.9.0 with the password still in place. This gets the new OTA code onto the chip.
  • Only then replace password: with encryption: and flash again.

If you do it in the wrong order you will find out the annoying way: a device that no longer accepts your update and a USB cable you have to go and find. For anything mounted inside a wall box or an enclosure, I would do the first pass for every device, confirm each one is online and reporting 2026.9, and only then start the second pass.

The deadline is also real: the unencrypted OTA path is scheduled for removal in 2027.3.0. That is plenty of time, but it is a hard stop, and anything still on a password by then will need a cable to recover. The patch release 2026.9.1 (29 September) also includes a fix around OTA encryption key handling in safe mode, so if you are updating now, start from 2026.9.1 rather than 2026.9.0.

Why I care about this on a local-first network

“It is only my LAN” is the argument I have made for years, and it is not wrong, but it is lazy. My LAN also carries a pile of cheap IoT gear, guest devices and the occasional thing I have not audited. Firmware is the most privileged payload on any device I own, and sending it over a network in a form anyone on the segment can read or tamper with is exactly the kind of shortcut I would call out in a cloud product. Applying the same standard to my own gear is only fair.

There is a related option from 2026.4 that is worth knowing about: signed OTA verification. It checks the firmware signature during an update without requiring hardware Secure Boot, so you do not burn any eFuses. In private key mode ESPHome signs at build time, and in public key mode only the public key lives on the device while you sign the binaries elsewhere, for example in CI. That is a different protection (is this firmware really mine?) from encrypted transfer (can anyone read it on the wire?), and the two complement each other. I will cover signing in its own post once I have lived with it for a while.

Side effects worth knowing

Encryption used to be expensive on small chips, and this release makes it cheaper. The notes quote the API encryption flash cost on an ESP8266 d1 mini dropping from 80.9 KB to 41.9 KB, with static RAM falling from 1376 bytes to 48 bytes, and the ESP8266 Noise handshake going from about 580 ms to about 300 ms. If you were leaving encryption off on tiny boards because of the footprint, that excuse just got a lot weaker.

Builds are faster too. PlatformIO installs now run in parallel, and a no-op rebuild of a six-library config dropped from 2.9 s to 0.4 s. Those are the project’s own CI figures, so your mileage will vary, but the direction is right if you compile on a modest machine.

Green printed circuit board with capacitors and microchips
Photo: Pixabay via Pexels

Before you update: my short checklist

  • Back up your ESPHome config folder first. It takes a minute and saves an evening.
  • Check which devices actually have an api: encryption key. Those without one will not get encrypted OTA until you add it.
  • Read the breaking changes. The Modbus Controller got a notable shake-up (custom_command became custom_pdu, and broadcast address 0 is now rejected), and a burned custom eFuse MAC now applies to Ethernet, Bluetooth and 802.15.4 addresses as well. That last one can change MAC addresses on upgrade, which matters if your router has DHCP reservations. The ignore_efuse_custom_mac: true option keeps the old behaviour.
  • Update one low-stakes device first, such as a desk sensor, not the one that controls your heating.
  • Do the password-to-encryption switch as a separate, second round.

One more heads-up: the release notes say the native ESP8266 toolchain is expected in 2026.10.0, which has not been published as of today. I would wait for that and its own breaking changes before touching old ESP8266 boards a second time.

My take

This is the kind of release I like: no flashy feature, just a long-standing weak spot fixed properly, with a deadline and a clear migration path. The two-step dance is a little fiddly, but it is documented, and it is a one-time cost. If you run ESPHome devices you cannot easily reach, give yourself a quiet afternoon, go slowly, and let the first batch prove itself before you do the rest.

Sources: ESPHome 2026.9.0 release notes; ESPHome 2026.4.0 announcement (signed OTA). Header photo from Pexels.

Leave a Reply

Your email address will not be published. Required fields are marked *