ORDER BY optimization issue
Normally you want to throw away as many rows as you can, as quickly as you can.  That doesn't seem likely here, unfortunately.

All you have is 'deleted = 0' for each table, so MySQL will pick a table to start with.  In your explain, it picked user_details, resulting in 1.5M rows being used.

Do the other tables have fewer active rows?  If so, you'd want to start with that table instead.

Once it picks a table, it will join across.  If we're starting with user_details, you're off to user_accounts_user_details, so you'll want an index on user_details(deleted, id) so the ids can be found via the index.

Since you're coming into user_accounts_user_details with the contact_id, you'll want to start your index with that.  We know that deleted=0 there, too, so add that.  And, once again, you'll want the id for the next table in your index.  I think that means user_account_user_details(contact_id, deleted, account_id).

We'll take that account_id over to user_accounts, so we'll need an index there.  We still have deleted=0, and we're not continuing on to other tables, so try user_accounts(id, deleted).

Depending on the quantity and size of the columns you're SELECTing from each table, you can add them at the end of the indexes, which can keep MySQL from having to read the underlying row from disk.  In your case, it looks like you're SELECTing a good number of long columns, which I wouldn't add to the composite indexes described above.  I might be tempted to include user_accounts.name, since you use that in the ORDER BY clause.

I hope that helps.

If possible find some other way to reduce the number of rows more quickly.  Can you limit by date, or something else?  Starting with 10 records in the first table would be so much better than starting with 1M.

Good luck.