Your code has one major issue for the binding, namely:
QSqlQuery::QSqlQuery(const QString & query = QString(), QSqlDatabase db = QSqlDatabase())
Constructs a QSqlQuery object using the SQL query and the database db. If db is not specified, or is invalid, the application's default database is used. If query is not an empty string, it will be executed.
So, your query will be executed during the construction since it is not empty, and the bind is already too late for that.
I would personally construct the instance with an empty string as the default, and then do an explicit preparation as per documentation.
So, I would write something like this:
QSqlQuery wordQuery();
wordQuery.setForwardOnly(true);
wordQuery.prepare("SELECT id, word FROM Words WHERE ref_id = :ref_id");
wordQuery.bindValue(":ref_id", refId);
if (!wordQuery.exec())
qDebug() << "SQL QUERY ERROR:" << wordQuery.lastError().text();
while (wordQuery.next()) {
// obtain data from `wordQuery` using QSqlQuery::value( )
}