A LEFT JOIN keeps every left row by filling the right side with NULLs when nothing matches. WHERE then runs after the join. A filter like b.status = 'PAID' is false (really UNKNOWN) for those NULL rows, so they are removed. The unmatched left rows are gone, and you are left with what an INNER JOIN would have given.
Example
customers has 3 rows. Only customer 1 has a paid order. Customer 2 has a refunded order. Customer 3 has no orders.
-- Looks like a left join, behaves like an inner join SELECT c.id, o.order_id FROM customers c LEFT JOIN orders o ON o.customer_id = c.id WHERE o.status = 'PAID'; -- 1 row (customer 1) -- Condition moved into ON: all customers stay SELECT c.id, o.order_id FROM customers c LEFT JOIN orders o ON o.customer_id = c.id AND o.status = 'PAID'; -- 3 rows (customers 2 and 3 have NULL order_id)
The second form says "attach paid orders where they exist, keep everyone". That is usually what a report on all customers wants.
How to spot it
The tell is a row count. Run SELECT COUNT(*) on the left table, then on the joined result. With a left join and a one-to-one or one-to-many relationship, the result should never have fewer rows than the base table. If it does, a WHERE condition on the right table is filtering out the NULL-extended rows.
When WHERE on the right side is correct
Sometimes you want that effect. WHERE o.order_id IS NULL after a left join is the anti-join pattern, "customers with no orders". There the NULL rows are exactly what you want to keep. So the rule is not "never filter the right table in WHERE". The rule is to know that you are choosing between "keep all left rows" and "keep only matches", and to write the condition where it does what you mean.