I didn't put those values 11, 6, and 20 in there. Where did they come from and what are they?

They're the columns' "Display Width"

Well, for an integer type (the value in parentheses called the display width of the field. This is different from (and somewhat less intuitive than) the parenthesised value in character fields—such as VARCHAR(10)—where it's the maximum number of characters you can store in the field, and for floating types where it describes the total number of digits you can store. The display width for integers... well it doesn't seem to do much really, on the surface.

The c1 and c3 columns use explicit display widths. The c2 column uses the default display width, which is just enough to contain the largest amount of characters in a BIGINT (including the sign). The largest negative BIGINT is -9223372036854775808, which if you count carefully you'll see is 20 characters. For similar reason, the default display with of an INT (with largest negative value -2147483648, go on, count 'em) is 11, and so on.

Note that ZEROFILL implicitly makes the column unsigned so it cannot store negative numbers. You couldn't, for example, see a number like -000123 in such a column.

The ZEROFILL option fills up the return value with zeros, as you might have guessed. It turns numbers like 123 into numbers like 000123, assuming your display width is 6. Let's see what it means in our table:

So it should be clear that the display width does not limit the amount of values you store in the column—you still get 123456 in a column with a display width of 5—but simply put, it affects how the values appear when they're padded.

What's the point if it doesn't work without ZEROFILL?

Ah, but it does. Well, it does if you want it to. The mysql command-line client doesn't use the display width unless the field is full of zeroes, but other client applications can (and do). The display width is available to applications through the API, so they can use it to pad (with spaces, dashes, or whatever you like) the values.

This code reads the display width of the c3 column (which we know is 30, from the code above) from the column's metadata into a variable $c3length, and uses that value to provided a width to the format specifier %d (for decimal integer), so you get the expression %${c3length}d, which evaluates as %30d. This prints the value of $row['c3'] as an integer in a field 30 characters wide, right justified and space-padded.

The same sort of code exists in other languages; in Java, the java.sql.ResultSetMetaData interface provides the getColumnDisplaySize method, and Java's String.format method works similarly to the printf code above.

In short...

You can ignore the display widths if you don't use them. The defaults are enough to display any value compatible with the type, and won't cause you trouble if your application uses the display width without your knowledge.

If you need to zero-pad your numbers, display width lets you say how much padding you need, but you'll need to make sure your application deals with number larger than that width either by ensuring it can handle them, or that your business logic prevents them.

If you want to display space-padded numbers in plaintext reports or other fixed-width output formats and you want to store the column's display width with the other column metadata at the database (and where else would you put it?), use the display width.