This is one reason why other DBMSs that better support standard SQL employ an independent 'sequence' rather than a special autoincrement field as MySQL has it. In PostgreSQL, for example, you'd
create sequence foo
(You can actually have a lot more than that - the starting point, the size of the increment, its minimum and maximum values, and whether or not it wraps around at the ends.)
The sequence has a number of functions that can be used to query its state. currval('foo') is the current value of the "foo" sequence, nextval('foo') kicks the sequence one notch and returns the new value, and setval('foo', newvalue) also does the obvious thing.
Using it in a table definition is straightforward:
CREATE TABLE 'bar' (
id integer DEFAULT nextval('foo'),
...
)
(PostgreSQL even has a bit of syntactic sugar to not only simplify this but make the field a primary key for indexing as well.)
Sequences run independently of the table - it doesn't matter what's in the table or not in the table, and it doesn't matter how many concurrent inserts are happening - they all see the same sequence so nextval() won't return the same value twice (unless the sequence is set to wrap around and it manages to wrap all the way around!)