[...] use one connection per thread
Yes, this is likely the best approach in most cases. You might also consider a connection pool. Could a generalised connection pool be something of value in Boost? I may have mentioned this before in relation to MySQL.
Boost.MySQL has recently added dedicated connection_pool functionality. I don't see how sqlite and MySQL could share pooling functionality, since one is sync and the other is async. Additionally, efficient pooling relies on database-specific details, which are not exposed to the end user but are used internally to boost performance.
On another subject, I note that the proposed API extensively uses string_view as a function return type. For example, field::column_name() returns a string_view. I consider this an anti-pattern. (In case anyone doesn't understand the issue, the danger is that the view will be dangling if the caller keeps it beyond the life of... some other object; I was going to write "the field object", but I'm not sure if that's right; maybe the row? The docs don't say.) In the case of e.g. column_name(), std::string's small buffer optimisation means that returning a std::string will not involve dynamic allocation unless the column name is more than maybe 23 characters long, which surely must be sufficient in practically all cases. If you really worry about long column names, please have a separate method (e.g. column_name_view()) whose name is a warning that it returns a view.
MSVC standard lib and stdlibc++ std::string's have 15 characters of static capacity. Regards, Ruben.