All posts

September 13, 2026

ASSOC-REJECT status_code=1027: when the access point is full, Android blames your password

A new phone refused to join the rack's Wi-Fi and Android reported a wrong password. The supplicant log said ASSOC-REJECT — refused before the passphrase was ever checked. The access point's station table was full, and one of the slots was held by a device that wasn't ours.

We added a phone to the rack and it would not join the network. Android said the password was wrong. The password was not wrong. It took longer than it should have to work out why, so here is the whole thing, including the part where we were looking at the wrong layer for an hour.

The symptom

A new handset, freshly wiped, joining the same Wi-Fi network the other phones were sitting on. The network the host itself runs. Same SSID, same passphrase, pasted from the same place.

The phone's UI did what Android always does when a join fails: it fell back to Check password and try again. In logcat it looked like this — a join attempt, a refusal, and then nothing:

WifiNetworkSelector: connect-network
ClientModeImpl: rejoin FAILED

So we did the obvious things. Retyped the passphrase by hand rather than pasting it. Forgot the network and re-added it. Checked for a stray leading space in the stored PSK. Confirmed another phone could still join with the same credential — it could, immediately, which should have been the first real clue and instead read as "so the network is fine, it must be this handset."

We then spent a while on the handset. Different band, forget-all-networks, reset network settings, reboot. Same refusal every time.

The line that actually mattered

Turning up the Wi-Fi logs on the supplicant gave us the real event:

wpa_supplicant: ASSOC-REJECT status_code=1027

That single line relocates the problem, and it is worth being precise about why.

An 802.11 client joins in stages. It associates with the access point first, and only then runs the 4-way handshake that proves it knows the passphrase. Those are separate steps in that order. ASSOC-REJECT means the access point refused at the first one — before the passphrase was presented, let alone checked.

So whatever went wrong, the credential was never part of the conversation. Every minute we spent on the passphrase was spent on a step the phone never reached. Android's "check your password" message is a generic fallback for "association did not complete", and it is actively misleading here: it names the one thing that had definitively not failed.

If you take one thing from this post, take that. ASSOC-REJECT in the log and wrong password on the screen are not consistent with each other, and the log wins.

Why it was refused

The host's onboard radio was out of room.

An access point keeps a table of associated stations, and that table has a finite number of slots. Ours was full. The refusal was the access point saying so in the only way the protocol gives it, at the only point in the exchange where it can.

One command would have told us in about a second, and it is now the first thing we run:

iw dev wlan0 station dump | grep -c '^Station'

That prints the number of stations currently associated. Compare it to the number of devices you expect to be associated. If those two numbers disagree, stop looking at the new device — something else is holding a slot.

Which is exactly what had happened. One of the slots was not ours. A Redmi handset belonging to nobody in the rack had attached to the network and was quietly occupying a place in the table. We evicted it with a MAC deny entry (deny_mac_file in the AP config), the slot freed, and the new phone associated on the next attempt with no other change. Same passphrase we had been retyping all along.

What we changed

Three things, in order of how much they were worth.

The station count is now the first diagnostic, not the last. Any "this device won't join" report starts with station dump and a count, before anyone touches a credential. It is one command and it either exonerates the network or finds the problem outright.

The AP has an explicit deny list. A device that is not part of the rack should not be able to take a slot, and until this happened nothing stopped one. That is a small hardening job we had not thought to do because we had never hit the ceiling before — with room to spare, a squatter costs nothing and is invisible.

We accepted that one radio has a ceiling. This is the part with no clever fix. Growing past what the onboard radio will hold means a second radio, not a configuration flag. We would rather know that now, as a planning constraint, than discover it during a deploy.

Being honest about the numbers

We are deliberately not publishing "the limit is N" as a general fact, because it is not one. The number of stations an access point will hold depends on the chipset, the driver, the AP software and how it was configured — and the figure that gets quoted for consumer hardware is frequently not the figure you actually get. Ours was lower than we would have guessed, which is the entire reason this cost us an afternoon.

What generalises is not the number. It is the shape:

  • ASSOC-REJECT means the refusal happened before authentication, so the passphrase is not your problem no matter what the phone's UI says.
  • A full station table produces exactly this signature.
  • The count of associated stations is cheap to check and is the fastest way to tell "this device is broken" from "this network is full".
  • Something you do not own can be holding a slot.

Where this is not your bug

If the join fails after association — a 4-way handshake timeout, or an explicit WRONG_KEY / AUTH_FAILED in the supplicant log — then it really can be the credential, and this post does not apply to you. The distinction is visible in the logs and nowhere else, which is the frustrating part: the one screen every user looks at is the one that cannot tell you which case you are in.

And if you are running a handful of devices against a home router with plenty of headroom, you will probably never meet this. It only shows up at the ceiling, and the ceiling is usually somewhere you were not expecting to find one.


We rent physical Android phones by the minute, which means we operate the rack these notes come out of. If you want a real handset over real ADB without running the hardware yourself, that is what DeviceRent is. If you are building your own lab, the design notes on the rack cover the rest of the constraints.