Skip to content

MySQL - BIT

The BIT data type in MySQL is used for storing bit-field values. It is ideal for storing binary data, especially boolean flags or sets of states, in a very storage-efficient manner. This tutorial explores how to use the BIT type, its practical applications, and how to handle it correctly in your queries and applications.

The BIT(M) data type defines a column that can store M bits of data. M can range from 1 to 64. If you omit M, it defaults to BIT(1).

column_name BIT(M)

For example, a BIT(8) column can store 8 bits of data, representing any integer value from 0 (binary 00000000) to 255 (binary 11111111).

To insert bit values directly, you can use binary literal notations. The b'value' and 0bvalue notations are standard. The leading b is case-insensitive, but the 0b prefix is case-sensitive.

-- Valid bit literals
INSERT INTO my_table (bit_column) VALUES (b'101'); -- Inserts the value 5
INSERT INTO my_table (bit_column) VALUES (B'110'); -- Inserts the value 6
INSERT INTO my_table (bit_column) VALUES (0b111); -- Inserts the value 7
-- Invalid bit literal (0B is not recognized)
INSERT INTO my_table (bit_column) VALUES (0B1000);

One of the most common points of confusion with the BIT type is how values are displayed. By default, many SQL clients show BIT values in a hexadecimal or unprintable binary format. You often need to explicitly cast them to read them as integers.

Let’s create a table with a BIT(4) column.

CREATE TABLE ItemStatus (
id INT AUTO_INCREMENT PRIMARY KEY,
item_name VARCHAR(100),
status_flags BIT(4)
);
-- Insert an integer value. MySQL converts it to bits.
-- 9 in binary is 1001.
INSERT INTO ItemStatus (item_name, status_flags) VALUES ('Sensor A', 9);
-- Insert a binary literal value.
-- b'0101' is 5 in decimal.
INSERT INTO ItemStatus (item_name, status_flags) VALUES ('Sensor B', b'0101');

A standard SELECT might produce unhelpful output:

SELECT * FROM ItemStatus;

To see the values in a readable format, you can cast them to an integer or view their binary representation:

-- To view as integers
SELECT id, item_name, CAST(status_flags AS UNSIGNED) as status_int FROM ItemStatus;
-- To view as binary strings
SELECT id, item_name, BIN(status_flags) as status_bin FROM ItemStatus;

Practical Use Case: Storing Configuration Flags

Section titled “Practical Use Case: Storing Configuration Flags”

A powerful use for BIT(M) is to pack multiple boolean settings into a single column. Let’s say we have user settings represented by a BIT(8) column:

  • Bit 0 (value 1): Email Notifications Enabled
  • Bit 1 (value 2): Dark Mode Enabled
  • Bit 2 (value 4): Two-Factor Auth Enabled
  • Bit 3 (value 8): Marketing Emails Opt-In

You can manipulate these flags using bitwise operators:

-- Enable Dark Mode (Bit 1) for user 123
UPDATE UserSettings SET config_flags = config_flags | b'00000010' WHERE user_id = 123;
-- Disable Email Notifications (Bit 0) for user 123
UPDATE UserSettings SET config_flags = config_flags & ~b'00000001' WHERE user_id = 123;
-- Find all users with Two-Factor Auth enabled (Bit 2)
SELECT * FROM UserSettings WHERE config_flags & b'00000100';

For a single true/false value, you have several options in MySQL:

  • BIT(1): The most storage-efficient option. It physically stores a single bit.
  • BOOLEAN or BOOL: These are synonyms for TINYINT(1). They are not true boolean types.
  • TINYINT(1): Stores an 8-bit integer, but is conventionally used to represent booleans (0 for false, 1 for true).

Recommendation: For single boolean flags, TINYINT(1) is often the most practical choice. It is easier to work with in most application frameworks and ORMs, which typically map it directly to a native boolean type, avoiding the retrieval issues associated with BIT(1).

Different database connectors handle BIT types differently. Some may return it as a raw byte buffer, which you need to convert in your application code.

PHP
Node.js
Java
Python
// PHP (using mysqli)
// By default, mysqli may return BIT values as strings that need conversion.
$mysqli = new mysqli(...);
$result = $mysqli->query("SELECT status_flags FROM ItemStatus WHERE id = 1");
$row = $result->fetch_assoc();
// The value might be a binary string. Get its integer value with ord().
$status_value = ord($row['status_flags']); // 9
echo "Status integer value: $status_value";
// Node.js (using mysql2)
// The mysql2 driver can be configured to handle BIT(1) as booleans.
const connection = await mysql.createConnection({
// ... credentials ...
// This setting helps with BIT(1)
typeCast: function(field, next) {
if (field.type === 'BIT' && field.length === 1) {
return (field.buffer()[0] === 1);
}
return next();
}
});
// For BIT(M), it will return a Buffer
const [rows] = await connection.execute('SELECT status_flags FROM ItemStatus WHERE id = 1');
const buffer = rows[0].status_flags; // <Buffer 09>
const intValue = buffer.readUInt8(0); // 9
console.log(`Status integer value: ${intValue}`);
// Java (using JDBC)
// JDBC's getObject() or getBoolean() for BIT(1) usually works well.
ResultSet rs = statement.executeQuery("SELECT status_flags FROM ItemStatus WHERE id = 1");
if (rs.next()) {
// For BIT(1), you can often use getBoolean()
// boolean flag = rs.getBoolean("status_flags");
// For BIT(M), you might get a byte array
byte[] statusBytes = rs.getBytes("status_flags");
if (statusBytes != null && statusBytes.length > 0) {
// A simple conversion for a single-byte BIT field
int statusValue = statusBytes[0] & 0xFF;
System.out.println("Status integer value: " + statusValue); // 9
}
}
# Python (using mysql-connector-python)
# The connector often converts BIT values to integers automatically.
cursor.execute("SELECT id, item_name, status_flags FROM ItemStatus")
result = cursor.fetchall()
print("Table Data:")
for row in result:
# row[2] will likely be the integer representation
print(f"ID: {row[0]}, Name: {row[1]}, Status: {row[2]}")
# Output would be:
# ID: 1, Name: Sensor A, Status: 9
# ID: 2, Name: Sensor B, Status: 5