Non è carino, ma penso che questo lo faccia e forse può essere la base di qualcosa di meno ingombrante. Nota che uso un INNER JOIN "falso" solo per inizializzare una variabile per la prima volta, non ha altro ruolo.
SELECT ID,
supplier,
qty,
cumulative_qty
FROM
(
SELECT
ID,
supplier,
qty,
-- next line keeps a running total quantity by supplier id
@cumulative_quantity := if (@sup <> supplier, qty, @cumulative_quantity + qty) as cumulative_qty,
-- next is 0 for running total < 5 by supplier, 1 the first time >= 5, and ++ after
@reached_five := if (@cumulative_quantity < 5, 0, if (@sup <> supplier, 1, @reached_five + 1)) as reached_five,
-- next takes note of changes in supplier being processed
@sup := if(@sup <> supplier, supplier, @sup) as sup
FROM
(
--this subquery is key for getting things in supplier order, by descending id
SELECT *
FROM `sample_table`
ORDER BY supplier, ID DESC
) reverse_order_by_id
INNER JOIN
(
-- initialize the variables used to their first ever values
SELECT @cumulative_quantity := 0, @sup := 0, @reached_five := 0
) only_here_to_initialize_variables
) t_alias
where reached_five <= 1 -- only get things up through the time we first get to 5 or above.