diff --git a/mollom.install b/mollom.install
index 5dda6d4..355a95b 100644
--- a/mollom.install
+++ b/mollom.install
@@ -114,14 +114,14 @@ function mollom_schema() {
         'not null' => TRUE,
         'default' => '',
       ),
-      'contentId' => array(
+      'content_id' => array(
         'description' => 'Content ID returned by Mollom.',
         'type' => 'varchar',
         'length' => 128,
         'not null' => TRUE,
         'default' => '',
       ),
-      'captchaId' => array(
+      'captcha_id' => array(
         'description' => 'CAPTCHA ID returned by Mollom.',
         'type' => 'varchar',
         'length' => 128,
@@ -152,13 +152,13 @@ function mollom_schema() {
       // would have an unintended meaning. Also, values are stored in individual
       // columns, so as to be able to join and filter/sort on these values for
       // improved content moderation.
-      'spamScore' => array(
+      'spam_score' => array(
         'description' => 'Text analysis spam check result.',
         'type' => 'float',
         'size' => 'tiny',
         'not null' => FALSE,
       ),
-      'spamClassification' => array(
+      'spam_classification' => array(
         'description' => 'Text analysis final spam classification result.',
         'type' => 'varchar',
         'length' => 16,
@@ -170,13 +170,13 @@ function mollom_schema() {
         'size' => 'tiny',
         'not null' => FALSE,
       ),
-      'qualityScore' => array(
+      'quality_score' => array(
         'description' => 'Text analysis quality check result.',
         'type' => 'float',
         'size' => 'tiny',
         'not null' => FALSE,
       ),
-      'profanityScore' => array(
+      'profanity_score' => array(
         'description' => 'Text analysis profanity check result.',
         'type' => 'float',
         'size' => 'tiny',
@@ -233,8 +233,8 @@ function mollom_schema() {
        ),
     ),
     'indexes' => array(
-      'contentId' => array('contentId'),
-      'captchaId' => array('captchaId'),
+      'content_id' => array('content_id'),
+      'captcha_id' => array('captcha_id'),
     ),
     'primary key' => array('entity', 'id'),
     'foreign keys' => array(
@@ -1216,3 +1216,60 @@ function mollom_update_7212() {
   variable_set('mollom_fai_entity_types', variable_get('mollom_fai_entity_types', array('comment' => 'comment')));
   variable_set('mollom_fai_dialog', variable_get('mollom_fai_dialog', 'mollom'));
 }
+
+/**
+ * Change all mixedCase database columns and indexes to underscore separated.
+ */
+function mollom_update_7213() {
+  db_drop_index('mollom', 'contentId');
+  db_drop_index('mollom', 'captchaId');
+  if (db_field_exists('mollom', 'contentId')) {
+    db_change_field('mollom', 'contentId', 'content_id', array(
+      'description' => 'Content ID returned by Mollom.',
+      'type' => 'varchar',
+      'length' => 128,
+      'not null' => TRUE,
+      'default' => '',
+    ));
+  }
+  if (db_field_exists('mollom', 'captchaId')) {
+    db_change_field('mollom', 'captchaId', 'captcha_id', array(
+      'description' => 'CAPTCHA ID returned by Mollom.',
+      'type' => 'varchar',
+      'length' => 128,
+    ));
+  }
+  if (db_field_exists('mollom', 'spamScore')) {
+    db_change_field('mollom', 'spamScore', 'spam_score', array(
+      'description' => 'Text analysis spam check result.',
+      'type' => 'float',
+      'size' => 'tiny',
+      'not null' => FALSE,
+    ));
+  }
+  if (db_field_exists('mollom', 'spamClassification')) {
+    db_change_field('mollom', 'spamClassification', 'spam_classification', array(
+      'description' => 'Test analysis final spam classification result.',
+      'type' => 'varchar',
+      'length' => 16,
+    ));
+  }
+  if (db_field_exists('mollom', 'qualityScore')) {
+    db_change_field('mollom', 'qualityScore', 'quality_score', array(
+      'description' => 'Text analysis quality check result.',
+      'type' => 'float',
+      'size' => 'tiny',
+      'not null' => FALSE,
+    ));
+  }
+  if (db_field_exists('mollom', 'profanityScore')) {
+    db_change_field('mollom', 'profanityScore', 'profanity_score', array(
+      'description' => 'Text analysis profanity check result.',
+      'type' => 'float',
+      'size' => 'tiny',
+      'not null' => FALSE,
+    ));
+  }
+  db_add_index('mollom', 'content_id', array('content_id'));
+  db_add_index('mollom', 'captcha_id', array('captcha_id'));
+}
diff --git a/mollom.module b/mollom.module
index bf238a3..7e5eaf7 100644
--- a/mollom.module
+++ b/mollom.module
@@ -340,8 +340,8 @@ function _mollom_access($permission = FALSE) {
  * primarily used for mails, messages, and posts, which pertain to forms
  * protected by Mollom that do no result in stored entities after submission.
  * For example, Contact module's contact form. They can be reported by anyone
- * having the link. $id is expected to be either a {mollom}.contentId or
- * {mollom}.captchaId respectively.
+ * having the link. $id is expected to be either a {mollom}.content_id or
+ * {mollom}.captcha_id respectively.
  *
  * @see mollom_mail_add_report_link()
  *
@@ -430,13 +430,58 @@ function mollom_cron() {
 }
 
 /**
+ * Helper function to convert database column names to variable names.
+ *
+ * Database column names are separated by underscore, while some variable names
+ * are camelcased for backwards compatibility.
+ *
+ * @param stdClass $db_result
+ *   The database result object to convert.
+ * @param bool $reverse
+ *   True if the conversion should be run in reverse, from variable names to
+ *   database names.
+ * @return stdClass
+ *   The updated object with converted field names.
+ */
+function _mollom_convert_db_names($db_result, $reverse = FALSE) {
+  if (!is_object($db_result)) {
+    return $db_result;
+  }
+  $replace = array(
+    'content_id' => 'contentId',
+    'captcha_id' => 'captchaId',
+    'spam_score' => 'spamScore',
+    'spam_classification' => 'spamClassification',
+    'quality_score' => 'qualityScore',
+    'profanity_score' => 'profanityScore',
+  );
+  if ($reverse) {
+    $replace = array_flip($replace);
+  }
+
+  // Don't update the original data object but return a new converted clone.
+  $clone = new stdClass();
+  foreach($db_result as $prop => $value) {
+    if (array_key_exists($prop, $replace)) {
+      $clone->{$replace[$prop]} = $value;
+    }
+    else {
+      $clone->{$prop} = $value;
+    }
+  }
+  return $clone;
+}
+
+
+/**
  * Load a Mollom data record by contentId.
  *
  * @param $contentId
  *   The contentId to retrieve data for.
  */
 function mollom_content_load($contentId) {
-  return mollom_db_query_range('SELECT * FROM {mollom} WHERE contentId = :contentId', 0, 1, array(':contentId' => $contentId))->fetchObject();
+  $data = mollom_db_query_range('SELECT * FROM {mollom} WHERE content_id = :contentId', 0, 1, array(':contentId' => $contentId))->fetchObject();
+  return _mollom_convert_db_names($data);
 }
 
 /**
@@ -448,7 +493,8 @@ function mollom_content_load($contentId) {
  *   The entity id to retrieve data for.
  */
 function mollom_data_load($entity, $id) {
-  return mollom_db_query_range('SELECT * FROM {mollom} WHERE entity = :entity AND id = :id', 0, 1, array(':entity' => $entity, ':id' => $id))->fetchObject();
+  $data = mollom_db_query_range('SELECT * FROM {mollom} WHERE entity = :entity AND id = :id', 0, 1, array(':entity' => $entity, ':id' => $id))->fetchObject();
+  return _mollom_convert_db_names($data);
 }
 
 /**
@@ -461,7 +507,8 @@ function mollom_data_load($entity, $id) {
  *   The matching Mollom data as an array keyed by entity id.
  */
 function mollom_entity_type_load($type) {
-  return mollom_db_query('SELECT * FROM {mollom} WHERE entity = :entity', array(':entity' => $type))->fetchAllAssoc('id');
+  $data = mollom_db_query('SELECT * FROM {mollom} WHERE entity = :entity', array(':entity' => $type))->fetchAllAssoc('id');
+  return _mollom_convert_db_names($data);
 }
 
 /**
@@ -557,12 +604,16 @@ function mollom_data_save($data) {
     $data->languages = implode(',', $languages);
   }
 
+  // Convert mixed case variable names to lower-case _ separated database names.
+  $converted = _mollom_convert_db_names($data, TRUE);
+
   $update = db_query_range("SELECT 'id' FROM {mollom} WHERE entity = :entity AND id = :id", 0, 1, array(
     ':entity' => $data->entity,
     ':id' => $data->id,
   ))->fetchField();
-  drupal_write_record('mollom', $data, $update ? array('entity', $update) : array());
+  drupal_write_record('mollom', $converted, $update ? array('entity', $update) : array());
 
+  // Pass unconverted data to other modules for backwards compatibility.
   if (!$update) {
     module_invoke_all('mollom_data_insert', $data);
   }
@@ -3027,7 +3078,8 @@ function mollom_mail_add_report_link(array &$message, array $mollom) {
       $data = mollom_content_load($mollom['response']['content']['id']);
     }
     elseif (!empty($mollom['response']['captcha']['id'])) {
-      $data = mollom_db_query_range('SELECT * FROM {mollom} WHERE captchaId = :captchaId', 0, 1, array(':captchaId' => $mollom['response']['captcha']['id']))->fetchObject();
+      $db_data = mollom_db_query_range('SELECT * FROM {mollom} WHERE captcha_id = :captchaId', 0, 1, array(':captchaId' => $mollom['response']['captcha']['id']))->fetchObject();
+      $data = _mollom_convert_db_names($db_data);
     }
     if (!$data) {
       // @todo Mollom session data should have been saved earlier already;
