Find minutes with no data in database
Is this the only query on data that matters?  You have too many simple indexes.  For example, there's no reason to have an index on just sensor_id if you already have one with sensor_id in the front.    

CREATE TABLE `data` (
 `id` int(13) NOT NULL AUTO_INCREMENT,
 `sensor_id` int(13) NOT NULL,
 `datetime` datetime NOT NULL,
 `value` float NOT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `sensor_id_2` (`sensor_id`,`datetime`,`value`)
)


The minutes table is even worse.  There's only two columns but you have six indexes (the PRIMARY KEY is an index on id).  Three would be serious overkill.  

CREATE TABLE `minutes` (
 `id` int(13) NOT NULL AUTO_INCREMENT,
 `value` varchar(16) NOT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `value_id` (`value`, `id`),
 UNIQUE KEY `id_value` (`id`, `value`)
)


Your query looks weird to me.  You're doing string operations (LIKE) on a datetime field.  This probably means that you are skipping the index and almost certainly that you aren't using the index to limit the possible rows.  A more common form would be 

SELECT t.`value`, d.`sensor_id`, COUNT(t.`value`) as `numrows`
FROM `data` d
RIGHT JOIN `times` t
  ON TIME_FORMAT(d.`datetime`, '%H:%i') = t.`value`
WHERE d.`datetime` &gt;= '2014-11-05 00:00:00'
  AND d.`datetime` &lt;= '2014-11-05 23:59:00'
  AND d.`sensor_id` IN (1,2,3,4,5,999)
GROUP BY d.`sensor_id`, t.`value`
ORDER BY d.`sensor_id` ASC, t.`value` ASC


And you should be aware that when you specify IN, you are repeating the query once for each value.  So this query would run six times.  You may find it easier to run the six queries on the PHP side, as they'll be smaller.  This can also help your programming logic.   

You might want to look up EXPLAIN plans, as they should help hint at what your problems are.  You might consider posting your SQL and explain plan to Stack Overflow (hint, just add EXPLAIN before the SELECT and look at the results in an admin tool like phpMySQL).  

It's possible that the thing to do is to replace your DATETIME column with a DATE column and a minutes_id column.  Then your join would be on a fast integer join and you could do a straightforward date check.  

Rather than doing a RIGHT JOIN, you might be better off with a regular inner join.  Then look for missing times in PHP.  Outer joins (left and right) are much slower than properly indexed inner joins.  You may find it easier to look for the missing times in PHP than to have your database do it.  

I find it questionable to read all the data in and then use it.  It's often better to read the data and then use it immediately.  

$times = array();
for ( $hour = 0; $hour &lt; 24; $hour++ ) {
    for ( $minute = 0; $minute &lt; 60; $minute++ ) {
        $times[] = sprintf('%02u:%02u', $hour, $minute);
    }
}

reset($times);
$last_sensor = 0; // assumes that there is no sensor 0
while ( $s = $select-&gt;fetch_assoc() ) {
    if ( $s['sensor_id'] != $last_sensor ) {
        echo 'Sensor: ' . $s['sensor_id'] . PHP_EOL;
        $last_sensor = $s['sensor_id'];

        // clear any remaining times from the last sensor
        while ( list(, $time) = each($times) ) {
            echo "$time 0" . PHP_EOL;
        }
        reset($times);
    }

    // iterate through until we find the current time
    list(, $time) = each($times);
    while ( $time != $s['value'] ) {
        // mark the missing times
        echo "$time 0" . PHP_EOL;
        list(, $time) = each($times);
    }

    echo "$time {$s['numrows']}" . PHP_EOL;
}