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

PostgreSQL
SELECT department, STRING_AGG(name, ', ') FROM employees GROUP BY department;
MySQL
SELECT department, GROUP_CONCAT(name SEPARATOR ', ') FROM employees GROUP BY department;
The separator becomes optional syntax after SEPARATOR in MySQL rather than a mandatory positional argument.

Ordered concatenation

PostgreSQL
SELECT STRING_AGG(name, ', ' ORDER BY name) FROM employees;
MySQL
SELECT GROUP_CONCAT(name ORDER BY name SEPARATOR ', ') FROM employees;
ORDER BY moves from after the separator argument to before SEPARATOR.

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.