PostgreSQL STRING_AGG() to MySQL GROUP_CONCAT() Crosswalk
MySQL's GROUP_CONCAT() does the same job as PostgreSQL's STRING_AGG(), but makes the separator optional and applies a silent output-length cap PostgreSQL doesn't have.
Close equivalent Covers the common case, but has documented behavioral differences.
- PostgreSQL feature
STRING_AGG()- MySQL equivalent
GROUP_CONCAT()
Main limitation: PostgreSQL's STRING_AGG() requires the separator as a mandatory second argument; MySQL's GROUP_CONCAT() makes SEPARATOR optional, defaulting to a comma if omitted — dropping the separator argument when porting to MySQL is valid, but only if a comma default is actually what you want (use SEPARATOR '' for no separator instead).
Quick mapping
| PostgreSQL | STRING_AGG() |
|---|---|
| MySQL | GROUP_CONCAT() |
Examples
Concatenating grouped values with a separator
SELECT department, STRING_AGG(name, ', ') FROM employees GROUP BY department; SELECT department, GROUP_CONCAT(name SEPARATOR ', ') FROM employees GROUP BY department; Ordered concatenation
SELECT STRING_AGG(name, ', ' ORDER BY name) FROM employees; SELECT GROUP_CONCAT(name ORDER BY name SEPARATOR ', ') FROM employees; Caveats
Caveat
PostgreSQL's STRING_AGG() requires the separator as a mandatory second argument; MySQL's GROUP_CONCAT() makes SEPARATOR optional, defaulting to a comma if omitted — dropping the separator argument when porting to MySQL is valid, but only if a comma default is actually what you want (use SEPARATOR '' for no separator instead).
Caveat
ORDER BY placement moves from after the separator argument in PostgreSQL (STRING_AGG(expr, sep ORDER BY ...)) to before SEPARATOR in MySQL (GROUP_CONCAT(expr ORDER BY ... SEPARATOR sep)).
Caveat
MySQL's GROUP_CONCAT() output is silently truncated at the group_concat_max_len system variable (1024 bytes by default); PostgreSQL's STRING_AGG() has no equivalent cap — raise group_concat_max_len for any query that previously relied on PostgreSQL's unlimited-length behavior.
Caveat
MySQL's GROUP_CONCAT() supports an inline DISTINCT keyword; PostgreSQL's STRING_AGG() does not — if the PostgreSQL query pre-deduplicated via a subquery, the MySQL port can often be simplified to an inline DISTINCT within GROUP_CONCAT() instead.
References
- PostgreSQL docs — STRING_AGG (v17) — checked 2026-07-29
- MySQL Reference Manual — GROUP_CONCAT() (v8.4) — checked 2026-07-29
Last verified 2026-07-29.