I like the idea of ENUMs because they're explicit, whereas depending on a comment is pretty unfair to the user. Internally, ENUM is stored as 1 or 2 bytes, depending on the number of possible values (TINYINT is 1 byte). So lookups are going to be only slightly slower than TINYINT (an additional lookup to the information schema to determine the mapping to the right byte value to look for).
However, there are lots of caveats about ENUM implementations, and those often push people to other arrangements: In MySQL, ALTER TABLE on an ENUM can be expensive: the table locks, everything might get re-keyed... kinda bad. In PostgresSQL, you just can't alter an ENUM. You create a new column with the new set of options, copy values over, drop original column. Goodness help you if you've got indexes involved. (Although I hear that's changing? Or maybe it already has? Turns out as of 9.2 you can modify 'em! So probably about the same penalty as MySQL.)
So a lot of it will come down to your use case. If you're pretty confident the value set is complete or if you have the flexibility to manage an ALTER TABLE and its implications, consider ENUM for clarity.
But the third option, which you kindof mention, is the best: create a values table. Something like user_status_types with key column and label column (labels "blocked", "active", etc), and make it a foreign key reference of the status column in whatever other table(s). You can make the key a TINYINT, so space is still efficient. You still have a table lookup similar to the ENUM information schema lookup, but you have the flexibility to mess with the table without penalty, and it's still inherently clear to the user.
(VARCHAR is ... an option. Document databases enforce the schema at the application layer, as you'd be doing with VARCHAR, so it's a thing I guess, just not very RDMBS-like. The above blows that out of the water for performance, memory, clarity in the data layer, etc)