It basically comes down to the way async control flow interacts with resources which are in use. Say you have a classic program like this:
db = connect_to_db()
result = run_query(db, …)
result2 = run_query(db, …)
result3 = run_query(db, …)
return build_response(result, result2, result3)
If you make that async, you can make it potentially a good bit faster but you now have harder time reasoning about how many database connections are open at any point in time because it's not “one per thread” but rather a function of how many requests your async system allows to be inflight at any point in time.
The same problem arises for memory usage: if you allocate memory it's going to stay allocated until the last async response arrives and if that's non-trivial it means that the async work might not be worth the hassle because your concurrency is actually RAM-limited below the point where you see any benefit over synchronous execution.
One common challenge here is that it's usually quite easy to miss this being a problem no matter what style you use if you don't carefully test with real data volumes or under perfect conditions. For example, if my code looks like this:
result_1 = run_query(db)
result_2 = call_other_service()
return build_result(result1, result_2)
That'll run great during testing and async can make one of the calls effectively free but if either of those services gets slower all of the memory used for the intermediate state of the other calls still has to remain resident until it returns. I've seen this with databases and APIs, of course, but also unexpected things like auditd, syslog, directory services, NFS, etc. This is often reported as a problem with load-average / swapping because the system has a lot more requests in-progress than it typically does and wasn't tuned to keep that peak load within the physical capacity.
There are, of course, ways to guard against this but then it's a lot harder to have a language make synchronous-looking code run asynchronously and leaving out async/await isn't saving you much if you have to sprinkle synchronization primitives all over the place. That doesn't mean you don't do it, of course, but it means there isn't a shortcut.