query - асинхронная функция. К моменту получения данных из MySQL и вызова callback'а сама функция get_balance уже завершилась.
Оборачивайте вызов в Promise и используйте async/await. Примерно так:
async function get_balance(user_id) {
return new Promise((resolve, reject) => {
conn.query(
`SELECT * FROM users WHERE user_id = ${user_id}`,
(err, result) => {
if (err) {
reject(err);
}
console.log(result[0].balance) // 0 (как и надо)
resolve(result[0].balance);
},
);
});
}
const result = await get_balance(ctx.message.from.id);