Operations that block on IO should be done not just in a different coroutine, but specifically on a dispatcher intended to handle IO operations, such as
Dispatchers.IO. Those dispatchers typically have a higher thread limit since the threads aren't expected to do CPU-bound work and rather just spend most of their time sleeping, waiting for the OS to call them back.
Meanwhile, CPU-bound dispatchers like Dispatchers.Default are limited to the number of available cores because they're expected to always be using the processor and so having more threads than cores wouldn't make sense. So if you do blocking IO on such a dispatcher, you're keeping an entire core unuseable for no reason.