Possible to rewrite this query as a join?
You can get what you want with the following JOINed query, which ressembles very much your original one:

SELECT
    e.id, e.created_at, e.updated_at, e.user_id, e.type, e.follower, e.follower_pk, 
    max(e2.updated_at) AS last_follow_date
FROM
    events e
    LEFT JOIN events e2 
        ON      e2.user_id = e.user_id 
            AND e2.type = 'follow' 
            AND e2.updated_at &lt; e.updated_at
            AND e.type = 'unfollow' 
WHERE
    e.user_id = 1
GROUP BY
    e.id 
ORDER BY
    e.id, e.updated_at ;


With regard to performance, your queries will benefit from an index such as:

-- Index to improve performance
CREATE INDEX idx_events_user_id_type_updated_at
    ON events (user_id, type, updated_at) ;


The three columns user_id, type and updated_at appear in the JOIN condition. The order in which you want them is user_id (you make an = comparison, and is supposed to have high cardinality --i.e.: very many values--), type (you make an = comparison, cardinality = 2), updated_at checked with an inequality... MySQL is not good enough to use it as part of the index seek, but will make the index a covering one, and that will save from checking the original table.



Alternative: a slight twist on your original query, might save some time:

SELECT 
   e1.*, 
   case when type = 'unfollow' then
      (SELECT MAX(e2.updated_at) 
       FROM   events e2 
       WHERE  
                  e2.user_id = e1.user_id 
              AND e2.type = 'follow'
              AND e2.updated_at &lt; e1.updated_at
       )
   else NULL end AS last_follow_date
FROM   events e1
WHERE  e1.user_id = 1; 


You can check everything at dbfiddle here