Extracting certain records
First, let's go over some problems in your original query:

SELECT MAX(l.id) AS highestID, l.nid, n.status
..............
GROUP BY l.nid


... if there's more than one n.status for a given l.nid, you get a "random" row, decided by the optimizer (and not controllable by you).  I'm presuming that you only have one row here (we'll exploit this in a bit).

(SELECT end_time 
 FROM mbl
 WHERE id = (SELECT MAX(id) 
             FROM mbl
             WHERE nid = l.nid
             GROUP BY nid)) &lt;= NOW()


I'm presuming that id is still some sort of autogenerated value.  The problem is, outside of some very specific contexts, the only thing a db-generated id should be used for is its uniqueness.  Especially in situations where rows may be updated, max/min/ordering by ids rapidly becomes irrelevant.  You seem to be attempting to make sure the most-recently-added row has an end_time value in the past - if you have some sort of inserted_at or similar timestamp, that would be a better column to use.  It would also be helpful to know why you're looking for the greatest id in this case.  (However, as I don't know the other columns in you table, I'm stuck with it for the moment).

It turns out that your statement can be reduced to this:

SELECT Most_Recent.highestId, Most_Recent.nid, Node.status
FROM (SELECT nid, MAX(id) AS highestId
      FROM Mbl
      GROUP BY nid) Most_Recent
JOIN Node
  ON Node.nid = Most_Recent.nid
JOIN Mbl
  ON Mbl.nid = Most_Recent.nid
     AND Mbl.id = Most_Recent.highestId
     AND Mbl.end_time &lt;= NOW()


.... which not only eliminates a table reference, but your original version had issues with potential RBAR (row-by-agonizing-row)/Cartesian product plans.  Note that we're still required to join to Mbl twice, with the second time being solely to make sure that the most-recent row also has an end_time value in the past (this can't be done in the subquery, because that would collect the most-recent-id of rows with end_time in the past)