Yo optaría por algo como:
SELECT
c.id AS campaign_id,
COUNT(cc.id) AS code_count
FROM
campaigns c
LEFT JOIN campaign_codes cc on cc.campaign_id = c.id
AND cc.status = 0 -- Having this clause in the WHERE, effectively makes this an INNER JOIN
WHERE c.partner_id = 4
GROUP BY c.id
Moviendo el AND
a la cláusula de combinación hace que la combinación tenga éxito o falle, lo que es crucial para mantener las filas resultantes donde no hay una fila coincidente en la tabla 'derecha'.
Si estuviera en el WHERE
, las comparaciones con NULL (donde no hay código_campaña) fallarían y se eliminarían de los resultados.