When does a thread need a message queue?

Most examples using GNRC typically do

static msg_t msg_queue[MSG_QUEUE_SIZE];
msg_init_queue(msg_queue, ARRAY_SIZE(msg_queue));

because GNRC will use messages to pass packets to the handler thread. Is this still needed if GNRC is used via the SOCK API or will it then rely on the SOCK’s mbox?

No, if you are only using the sock API (and not e.g. the ping or udp command), you won’t need a message queue for the main thread.