🗃️

MariaDB Data Types

MariaDB supports all MySQL data types plus additional types for Oracle compatibility. Understanding the differences from PostgreSQL and SQLite is essential for schema design.

🔢 Numeric Types

TINYINT

A 1-byte signed integer. Commonly used for small flags or counters. TINYINT(1) is used internally by MariaDB as the storage type for BOOLEAN/BOOL.

Storage: 1 byte

Range: Signed: -128 to 127 | Unsigned: 0 to 255

vs PostgreSQL: PostgreSQL has no TINYINT. Use SMALLINT (2 bytes) or a CHECK constraint instead.

SMALLINT

A 2-byte signed integer. Useful when values are known to fit within a small range and storage efficiency matters.

Storage: 2 bytes

Range: Signed: -32,768 to 32,767 | Unsigned: 0 to 65,535

vs PostgreSQL: PostgreSQL SMALLINT is identical in size and signed range. No UNSIGNED modifier exists.

MEDIUMINT

A 3-byte signed integer. Unique to MySQL/MariaDB; useful for large counters that do not need the full 4-byte INT range.

Storage: 3 bytes

Range: Signed: -8,388,608 to 8,388,607 | Unsigned: 0 to 16,777,215

vs PostgreSQL: PostgreSQL has no MEDIUMINT. Use INTEGER (4 bytes) as the closest equivalent.

INT/ INTEGER

A 4-byte signed integer. The most commonly used integer type. The optional display width parameter (e.g. INT(11)) does not affect storage or range — it only hints at display padding with ZEROFILL.

Storage: 4 bytes

Range: Signed: -2,147,483,648 to 2,147,483,647 | Unsigned: 0 to 4,294,967,295

vs PostgreSQL: PostgreSQL INTEGER is identical in size and signed range. No UNSIGNED modifier or ZEROFILL display width exists.

BIGINT

An 8-byte signed integer. Use for very large counters, IDs, or bitmask fields that exceed INT range.

Storage: 8 bytes

Range: Signed: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 | Unsigned: 0 to 18,446,744,073,709,551,615

vs PostgreSQL: PostgreSQL BIGINT is identical in size and signed range. No UNSIGNED modifier exists.

DECIMAL/ NUMERIC

An exact fixed-point number stored as a string internally. DECIMAL(p, s) where p is total digits (precision, max 65) and s is digits after the decimal (scale, max 30). Ideal for monetary values.

Storage: Variable; approximately 4 bytes per 9 digits

Range: Precision up to 65 digits; scale up to 30 digits

vs PostgreSQL: PostgreSQL DECIMAL/NUMERIC is functionally identical. PostgreSQL allows unconstrained NUMERIC with no precision limit specified.

FLOAT

A single-precision 4-byte floating-point number. Approximate storage; not suitable for exact calculations. FLOAT(p) where p < 25 gives single precision.

Storage: 4 bytes

Range: Approximately ±3.402823466E+38, with ~7 significant decimal digits

vs PostgreSQL: PostgreSQL uses REAL for single-precision float (4 bytes). The semantics are equivalent.

DOUBLE/ REAL

A double-precision 8-byte floating-point number. Approximate storage; provides ~15 significant decimal digits. DOUBLE PRECISION is also accepted.

Storage: 8 bytes

Range: Approximately ±1.7976931348623157E+308, with ~15 significant decimal digits

vs PostgreSQL: PostgreSQL DOUBLE PRECISION is equivalent. PostgreSQL's REAL alias maps to single precision, not double — the opposite of MariaDB's REAL.

BIT

A fixed-length bit-field type. BIT(M) stores M bits (1 to 64). Useful for compact flag storage. Values are written as b'101' literals.

Storage: Approximately (M+7)/8 bytes

Range: BIT(1) to BIT(64)

vs PostgreSQL: PostgreSQL has BIT(n) and BIT VARYING(n) types with similar semantics, but bitwise operator syntax differs.

🔤 String Types

CHAR

A fixed-length character string. CHAR(n) always uses exactly n characters of storage (padded with spaces). n ranges from 0 to 255. Trailing spaces are stripped on retrieval.

Storage: n x character_set_maxlen bytes

Range: 0 to 255 characters

vs PostgreSQL: PostgreSQL CHAR(n) pads with spaces identically but preserves trailing spaces on retrieval, making comparison behavior subtly different.

VARCHAR

A variable-length character string. VARCHAR(n) stores up to n characters. n ranges from 0 to 65,535 (subject to row size limits and character set). A 1 or 2 byte length prefix is stored.

Storage: L + 1 or 2 bytes (where L is actual string length)

Range: 0 to 65,535 characters (row size limit applies)

vs PostgreSQL: PostgreSQL VARCHAR(n) is functionally identical. PostgreSQL also supports TEXT without a length limit as the preferred unbounded string type.

TINYTEXT

A variable-length text column with a maximum length of 255 bytes. Cannot have a DEFAULT value. Stored outside the row if large.

Storage: L + 1 bytes

Range: 0 to 255 bytes

vs PostgreSQL: PostgreSQL has no TINYTEXT. Use VARCHAR(255) or TEXT instead.

TEXT

A variable-length text column with a maximum length of 65,535 bytes (~64 KB). Cannot have a DEFAULT value. Commonly used for larger string content.

Storage: L + 2 bytes

Range: 0 to 65,535 bytes

vs PostgreSQL: PostgreSQL TEXT is unbounded (up to 1 GB) and supports DEFAULT values. Behavior differs significantly.

MEDIUMTEXT

A variable-length text column with a maximum length of 16,777,215 bytes (~16 MB). Cannot have a DEFAULT value.

Storage: L + 3 bytes

Range: 0 to 16,777,215 bytes

vs PostgreSQL: PostgreSQL has no MEDIUMTEXT. Use TEXT (unbounded) as the equivalent.

LONGTEXT

A variable-length text column with a maximum length of 4,294,967,295 bytes (~4 GB). Cannot have a DEFAULT value. Also used internally as the storage type for the JSON pseudo-type.

Storage: L + 4 bytes

Range: 0 to 4,294,967,295 bytes

vs PostgreSQL: PostgreSQL TEXT can store up to ~1 GB. LONGTEXT's theoretical 4 GB maximum exceeds PostgreSQL's TEXT limit.

BINARY

A fixed-length binary byte string. BINARY(n) stores exactly n bytes, right-padded with 0x00 bytes. Comparison is byte-by-byte (case-sensitive by nature).

Storage: n bytes

Range: 0 to 255 bytes

vs PostgreSQL: PostgreSQL uses bytea for binary data. BINARY(n) semantics (fixed-length, null-padded) have no direct PostgreSQL equivalent.

VARBINARY

A variable-length binary byte string. VARBINARY(n) stores up to n bytes with a length prefix. No character set conversion is performed.

Storage: L + 1 or 2 bytes

Range: 0 to 65,535 bytes

vs PostgreSQL: PostgreSQL uses bytea for variable-length binary data. bytea uses escape or hex encoding rather than raw byte storage.

TINYBLOB

A variable-length binary large object with a maximum length of 255 bytes. Stored as raw bytes; no character set semantics.

Storage: L + 1 bytes

Range: 0 to 255 bytes

vs PostgreSQL: PostgreSQL has no TINYBLOB. Use bytea instead.

BLOB

A variable-length binary large object with a maximum length of 65,535 bytes (~64 KB). Commonly used to store small files, images, or serialised data.

Storage: L + 2 bytes

Range: 0 to 65,535 bytes

vs PostgreSQL: PostgreSQL uses bytea for binary data. For very large objects, PostgreSQL also offers the large object (lo) interface.

MEDIUMBLOB

A variable-length binary large object with a maximum length of 16,777,215 bytes (~16 MB).

Storage: L + 3 bytes

Range: 0 to 16,777,215 bytes

vs PostgreSQL: PostgreSQL uses bytea (up to ~1 GB) or the large object interface for equivalent storage.

LONGBLOB

A variable-length binary large object with a maximum length of 4,294,967,295 bytes (~4 GB). Suitable for storing very large files in the database.

Storage: L + 4 bytes

Range: 0 to 4,294,967,295 bytes

vs PostgreSQL: PostgreSQL's bytea supports up to ~1 GB. For larger binary objects, the large object interface (pg_lo_*) must be used.

ENUM

A string column that can hold one value chosen from a predefined list of up to 65,535 members. Values are stored as integers internally. Comparison is case-insensitive by default.

Storage: 1 byte (up to 255 members) or 2 bytes (up to 65,535 members)

Range: 1 to 65,535 enumeration members

vs PostgreSQL: PostgreSQL supports ENUM as a named type created with CREATE TYPE ... AS ENUM. Unlike MariaDB, adding new values requires ALTER TYPE and cannot be done inline.

SET

A string column that can hold zero or more values chosen from a predefined list of up to 64 members. Multiple selected values are stored as a comma-separated string and internally as a bitmask.

Storage: 1, 2, 3, 4, or 8 bytes depending on number of members

Range: 0 to 64 set members

vs PostgreSQL: PostgreSQL has no SET type. The closest equivalent is an array of a custom ENUM type or a text[] column.

UUID

A native UUID type introduced in MariaDB 10.7. Stored as a 16-byte binary value internally but displayed as a standard 8-4-4-4-12 hex string. More efficient than storing UUIDs as CHAR(36).

Storage: 16 bytes

Range: 128-bit value (MariaDB 10.7+)

vs MySQL: MySQL does not have a native UUID type; UUIDs are typically stored as CHAR(36) or BINARY(16) with manual conversion.

vs PostgreSQL: PostgreSQL has a native UUID type with identical 16-byte storage and the same string representation.

📅 Date & Time Types

DATE

A calendar date value with no time component. Format: 'YYYY-MM-DD'. Supports a zero date '0000-00-00' unless NO_ZERO_DATE SQL mode is enabled.

Storage: 3 bytes

Range: '1000-01-01' to '9999-12-31'

vs PostgreSQL: PostgreSQL DATE is functionally identical but does not support zero dates. PostgreSQL range extends further back to '4713-01-01 BC'.

TIME

A time-of-day or elapsed time value. Format: 'HH:MM:SS[.ffffff]'. Can represent a negative duration or a value exceeding 24 hours for interval use cases.

Storage: 3 bytes (without fractional seconds); up to 6 bytes with microseconds

Range: '-838:59:59.999999' to '838:59:59.999999'

vs PostgreSQL: PostgreSQL TIME only represents time-of-day (0-24h). For durations/intervals, PostgreSQL uses the separate INTERVAL type.

DATETIME

A date and time value with no time zone awareness. Format: 'YYYY-MM-DD HH:MM:SS[.ffffff]'. Does not convert on insert based on session time zone.

Storage: 5 bytes (without fractional seconds); up to 8 bytes with microseconds

Range: '1000-01-01 00:00:00.000000' to '9999-12-31 23:59:59.999999'

vs PostgreSQL: PostgreSQL uses TIMESTAMP (without time zone) for the same purpose. PostgreSQL does not support the zero datetime '0000-00-00 00:00:00'.

TIMESTAMP

A date and time value stored as UTC seconds since the Unix epoch. Automatically converts to/from the session time zone on insert and retrieval. The first TIMESTAMP column in a table may auto-update on row modification unless explicitly configured otherwise.

Storage: 4 bytes (without fractional seconds); up to 7 bytes with microseconds

Range: '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC

vs PostgreSQL: PostgreSQL TIMESTAMP WITH TIME ZONE (TIMESTAMPTZ) converts to UTC on storage. PostgreSQL has no auto-update behavior; use triggers or DEFAULT NOW() explicitly.

YEAR

A 1-byte year value. Accepts 4-digit years or 2-digit shorthand (70-99 maps to 1970-1999, 00-69 maps to 2000-2069). The 2-digit form is deprecated.

Storage: 1 byte

Range: 1901 to 2155 (and 0000 for the zero year)

vs PostgreSQL: PostgreSQL has no YEAR type. Use SMALLINT or extract the year from a DATE/TIMESTAMP column.

📦 Other Types

BOOLEAN/ BOOL

A synonym for TINYINT(1). TRUE and FALSE keywords map to 1 and 0 respectively. Any non-zero integer is treated as true in a boolean context. MariaDB does not have a dedicated boolean storage type.

Storage: 1 byte

Range: 0 (FALSE) to 1 (TRUE); technically stores -128 to 127

vs PostgreSQL: PostgreSQL has a native BOOLEAN type with true/false/null semantics that is distinct from any integer type.

JSON

In MariaDB, JSON is an alias for LONGTEXT with a CHECK constraint that validates the value is well-formed JSON. Unlike MySQL, MariaDB does not have a separate binary JSON storage format. JSON functions work on the text value.

Storage: L + 4 bytes (LONGTEXT)

Range: 0 to 4,294,967,295 bytes

vs MySQL: MySQL stores JSON in an optimised binary format allowing partial in-place updates. MariaDB JSON is plain LONGTEXT with validation only.

vs PostgreSQL: PostgreSQL has two native types: JSON (text storage with validation) and JSONB (binary storage with indexing). PostgreSQL JSONB supports GIN indexing; MariaDB JSON does not.

INET4

A native IPv4 address type introduced in MariaDB 10.10. Stores addresses as a compact 4-byte binary value. Accepts dotted-decimal input ('192.168.1.1') and displays in the same format.

Storage: 4 bytes

Range: 0.0.0.0 to 255.255.255.255 (MariaDB 10.10+)

vs MySQL: MySQL has no native INET4 type. IPv4 addresses are typically stored as INT UNSIGNED and converted with INET_ATON()/INET_NTOA().

vs PostgreSQL: PostgreSQL has the INET type which stores both IPv4 and IPv6. MariaDB separates these into INET4 and INET6.

INET6

A native IPv6 address type introduced in MariaDB 10.10. Stores addresses as a compact 16-byte binary value. Accepts standard colon-hex notation and displays in canonical form.

Storage: 16 bytes

Range: :: to ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff (MariaDB 10.10+)

vs MySQL: MySQL has no native INET6 type. IPv6 addresses are typically stored as VARBINARY(16) or CHAR(39).

vs PostgreSQL: PostgreSQL's INET type covers both IPv4 and IPv6 in a single type with CIDR support. MariaDB INET6 is dedicated to IPv6 only.

ROW

A composite row type available only in MariaDB stored procedures (not in table column definitions). Allows a single variable to hold multiple named fields, similar to a record type in PL/pgSQL.

Storage: N/A (procedure variable only)

Range: N/A — for use in stored procedure variables only

vs MySQL: MySQL does not support the ROW type for stored procedure variables.

vs PostgreSQL: PostgreSQL supports composite types both as table row types and as standalone CREATE TYPE ... AS (field definitions). PostgreSQL's record type in PL/pgSQL is closely analogous.

Key Differences from PostgreSQL

  • No BOOLEAN type: MariaDB uses TINYINT(1) for boolean columns. PostgreSQL has a native BOOLEAN type.
  • AUTO_INCREMENT vs SERIAL: MariaDB uses AUTO_INCREMENT; PostgreSQL uses SERIAL or GENERATED AS IDENTITY.
  • TEXT vs VARCHAR: MariaDB TEXT cannot have a DEFAULT value; PostgreSQL TEXT can.
  • ENUM/SET: MariaDB (and MySQL) support ENUM and SET types; PostgreSQL uses CHECK constraints or separate lookup tables.
  • Unsigned integers: MariaDB supports UNSIGNED integers (e.g. INT UNSIGNED); PostgreSQL does not.