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
TINYINTA 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.
SMALLINTA 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.
MEDIUMINTA 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/ INTEGERA 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.
BIGINTAn 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/ NUMERICAn 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.
FLOATA 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/ REALA 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.
BITA 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
CHARA 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.
VARCHARA 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.
TINYTEXTA 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.
TEXTA 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.
MEDIUMTEXTA 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.
LONGTEXTA 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.
BINARYA 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.
VARBINARYA 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.
TINYBLOBA 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.
BLOBA 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.
MEDIUMBLOBA 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.
LONGBLOBA 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.
ENUMA 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.
SETA 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.
UUIDA 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
DATEA 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'.
TIMEA 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.
DATETIMEA 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'.
TIMESTAMPA 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.
YEARA 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/ BOOLA 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.
JSONIn 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.
INET4A 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.
INET6A 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.
ROWA 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.