Du måste sätta användarchecken i join, inte i where conditionlike så:
SELECT c.course_id,l.topic,l.id,l.vid_duration,p.*
FROM courses c
LEFT JOIN lessons l ON l.course_id=c.course_id
LEFT JOIN progress p ON l.id = p.lesson_id and p.user_id = :userid
WHERE c.slug = :course
Anledningen till att göra detta är att JOINS använder "vänster koppling" (vilket implicit är en yttre koppling". Denna typ av koppling betyder att om villkoret fungerar, returnera all kolumndata för den tabellen för den raden.. om hela villkoret inte fungerar, det kommer att returnera all data för tabeller som nämnts tidigare, men för tabellen som nämns i raden kommer det att returnera NULLS för alla dessa kolumner.
Jag ber om ursäkt för den beskrivningen, eftersom det är svårt att sätta ord på exakt hur en komplex yttre (eller vänster) sammanfogning fungerar utan att bli ordrik.